﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic;
using OpenTK.Graphics.ES11;
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using VAssimpNet;
using VIA.Domain.Repositories;
using VIA.Integration;
using VIA.Integration.Alarms;
using VIA.Integration.Domain;
using VIA.Integration.LeadShine;
using VIA.Project.Domain.Services;
using VIA.SiMoJi.Domain.Electronics;
using VIA.SiMoJi.Domain.Option;
using VIA.SiMoJi.Domain.ValueObject;
using VIA.SiMoJi.Domain.Vision;
using VT.Framework.Vision2D;
using static OpenCvSharp.Stitcher;
using static System.Runtime.InteropServices.JavaScript.JSType;
using static VIA.SiMoJi.Domain.Inspection.VisionStation;
using static VT.Framework.Utils.UtilTaskbarProgress;

namespace VIA.SiMoJi.Domain.Inspection
{
    public class BanYunStation : StationBase<BanYunStationOption>, ISuportClearAlarm
    {
        #region 字段
        public static bool IsUseSiMo1 => SignalPanel.Signal.IsUseSiMo1;
        public volatile VisionStation Vision;
        public volatile GongLiaoStation GongLiaoStation;
        public volatile SiMoStation SiMoStation;
        private InspectorOption _inspectorOption;
        public BanYunRunningStatus Status;
        private bool xyUnloadNGError;
        private bool flaySnapNGWraning;
        private bool ngTrayError;
        private bool ngNoReadyError;
        private bool liJuError;
        bool _isInitialized;
        #endregion

        #region 运动位置
        private const string X待机位 = "待机位";
        private const string X飞拍位1 = "飞拍位1";
        private const string X飞拍位2 = "飞拍位2";
        private const string XYR撕膜位1 = "撕膜位1";
        private const string XYR撕膜位2 = "撕膜位2";

        private const string 上相机读码位1 = "上相机读码位1";
        private const string 上相机读码位2 = "上相机读码位2";

        private const string C飞拍位1 = "飞拍位1";
        private const string C飞拍位2 = "飞拍位2";

        private const string Y待机位 = "待机位";
        private const string Y飞拍起始位 = "飞拍起始位";
        private const string Y夹爪1飞拍位 = "夹爪1飞拍位";
        private const string Y夹爪2飞拍位 = "夹爪2飞拍位";
        private const string Y夹爪3飞拍位 = "夹爪3飞拍位";
        private const string Y夹爪4飞拍位 = "夹爪4飞拍位";
        private const string Y夹爪5飞拍位 = "夹爪5飞拍位";
        private const string Y夹爪6飞拍位 = "夹爪6飞拍位";
        private const string Y夹爪7飞拍位 = "夹爪7飞拍位";
        private const string XY_NG下料位 = "NG下料位";
        private const string XY_压力测试位 = "压力测试位";
        private const string XY_NG下料避让位 = "NG放料避让位";
        private const string XYR取料位1 = "取料位1";
        private const string XYR取料位2 = "取料位2";

        private const string 待机位 = "待机位";
        private const string Z待机位 = "待机位";
        private const string Z取料位 = "取料位";
        private const string Z飞拍位 = "飞拍位";
        private const string Z放料位 = "放料位";
        private const string Z撕膜位1 = "撕膜位1";
        private const string Z撕膜位2 = "撕膜位2";
        public const string Z_NG放料位 = "NG放料位";
        public const string Z_压力测试起始位 = "压力测试起始位";
        public const string Z_压力测试终止位 = "压力测试终止位";
        private const string R_NG放料位 = "NG放料位";
        private const string R待机位 = "待机位";

        private const string BJ_张开位 = "张开位";
        private const string BJ_缩紧位 = "缩紧位";

        private const string 备用 = "备用";
        #endregion

        #region 事件
        public event EventHandler<string> StepsChanged;
        public event EventHandler<int> CurrentFeedTrayColChanged;
        public event EventHandler<TrayPointStatus[]> NozzelsProductChanged;
        public event EventHandler<(bool isOK, int count)> ProductCompleted;
        public event EventHandler<IEnumerable<LijuModel>> LiJuChanged;
        #endregion

        #region 设备报警
        [Alarm(true, AlarmLevel.Error, "XY轴放NG料超限位", Logical.Equal)]
        public bool XYUnloadNGError
        {
            get => xyUnloadNGError;
            set => NotifyAlarm(ref xyUnloadNGError, value);
        }
        [Alarm(true, AlarmLevel.Warning, "读码3次NG报警", Logical.Equal)]
        public bool FlaySnapNGWraning
        {
            get => flaySnapNGWraning;
            set => NotifyAlarm(ref flaySnapNGWraning, value);
        }
        [Alarm(true, AlarmLevel.Error, "NG料盘已满", Logical.Equal)]
        public bool NGTrayFullError
        {
            get => ngTrayError;
            set
            {
                NotifyAlarm(ref ngTrayError, value);
                if (value)
                {
                    NGTray.Instance.SetFull();
                }
            }
        }
        [Alarm(true, AlarmLevel.Error, "NG料盘未就绪", Logical.Equal)]
        public bool NGTrayNoReadyError
        {
            get => ngNoReadyError;
            set
            {
                NotifyAlarm(ref ngNoReadyError, value);
                if (value)
                {
                    NGTray.Instance.SetDisable();
                }
            }
        }
        [Alarm(true, AlarmLevel.Error, "吸嘴力矩异常", Logical.Equal)]
        public bool LiJuError
        {
            get => liJuError;
            set => NotifyAlarm(ref liJuError, value);
        }
        public int CurrentFeedTrayCol
        {
            get => Status.CurrentFeedTrayCol;
            set
            {
                Status.CurrentFeedTrayCol = value;
                CurrentFeedTrayColChanged.SafeInvoke(this, value);
            }
        }
        #endregion

        #region 硬件设备
        public NGXiaLiao NGXiaoLiao { get; private set; }
        public Electronic Electronic => Electronic.Default;
        [MotionPath(BJ_张开位)]
        [MotionPath(BJ_缩紧位)]
        public DmcAxis JiaZhuaBianJu_Axis { get; }

        [MotionPath(X待机位)]
        [MotionPath(XYR取料位1)]
        [MotionPath(XYR取料位2)]
        [MotionPath(X飞拍位1)]
        [MotionPath(X飞拍位2)]
        [MotionPath(XYR撕膜位1)]
        [MotionPath(XYR撕膜位2)]
        [MotionPath(XY_NG下料位)]
        [MotionPath(XY_NG下料避让位)]
        [MotionPath(XY_压力测试位)]
        [MotionPath(上相机读码位1)]
        [MotionPath(上相机读码位2)]
        [MotionPath(备用)]
        public DmcAxis X_Axis { get; }

        [MotionPath(Y待机位)]
        [MotionPath(XYR取料位1)]
        [MotionPath(XYR取料位2)]
        [MotionPath(XYR撕膜位1)]
        [MotionPath(XYR撕膜位2)]
        [MotionPath(Y飞拍起始位)]
        [MotionPath(Y夹爪1飞拍位)]
        [MotionPath(Y夹爪2飞拍位)]
        [MotionPath(Y夹爪3飞拍位)]
        [MotionPath(Y夹爪4飞拍位)]
        [MotionPath(Y夹爪5飞拍位)]
        [MotionPath(Y夹爪6飞拍位)]
        [MotionPath(Y夹爪7飞拍位)]
        [MotionPath(XY_NG下料位)]
        [MotionPath(XY_NG下料避让位)]
        [MotionPath(XY_压力测试位)]
        [MotionPath(上相机读码位1)]
        [MotionPath(上相机读码位2)]
        [MotionPath(备用)]
        public DmcAxis Y_Axis { get; }
        [MotionPath(C飞拍位1)]
        [MotionPath(C飞拍位2)]
        [MotionPath(备用)]
        public DmcAxis Camera_Axis { get; }
        [MotionPath(R待机位)]
        [MotionPath(XYR取料位1)]
        [MotionPath(XYR取料位2)]
        [MotionPath(XYR撕膜位1)]
        [MotionPath(XYR撕膜位2)]
        [MotionPath(R_NG放料位)]
        public DmcAxis R1_Axis { get; }
        [MotionPath(R待机位)]
        [MotionPath(XYR取料位1)]
        [MotionPath(XYR取料位2)]
        [MotionPath(XYR撕膜位1)]
        [MotionPath(XYR撕膜位2)]
        [MotionPath(R_NG放料位)]
        public DmcAxis R2_Axis { get; }
        [MotionPath(R待机位)]
        [MotionPath(XYR取料位1)]
        [MotionPath(XYR取料位2)]
        [MotionPath(XYR撕膜位1)]
        [MotionPath(XYR撕膜位2)]
        [MotionPath(R_NG放料位)]
        public DmcAxis R3_Axis { get; }
        [MotionPath(R待机位)]
        [MotionPath(XYR取料位1)]
        [MotionPath(XYR取料位2)]
        [MotionPath(XYR撕膜位1)]
        [MotionPath(XYR撕膜位2)]
        [MotionPath(R_NG放料位)]
        public DmcAxis R4_Axis { get; }
        [MotionPath(R待机位)]
        [MotionPath(XYR取料位1)]
        [MotionPath(XYR取料位2)]
        [MotionPath(XYR撕膜位1)]
        [MotionPath(XYR撕膜位2)]
        [MotionPath(R_NG放料位)]
        public DmcAxis R5_Axis { get; }
        [MotionPath(R待机位)]
        [MotionPath(XYR取料位1)]
        [MotionPath(XYR取料位2)]
        [MotionPath(XYR撕膜位1)]
        [MotionPath(XYR撕膜位2)]
        [MotionPath(R_NG放料位)]
        public DmcAxis R6_Axis { get; }
        [MotionPath(R待机位)]
        [MotionPath(XYR取料位1)]
        [MotionPath(XYR取料位2)]
        [MotionPath(XYR撕膜位1)]
        [MotionPath(XYR撕膜位2)]
        [MotionPath(R_NG放料位)]
        public DmcAxis R7_Axis { get; }
        [MotionPath(Z待机位)]
        [MotionPath(Z取料位)]
        [MotionPath(Z飞拍位)]
        [MotionPath(Z撕膜位1)]
        [MotionPath(Z撕膜位2)]
        [MotionPath(Z放料位)]
        [MotionPath(Z_NG放料位)]
        [MotionPath(Z_压力测试起始位)]
        [MotionPath(Z_压力测试终止位)]
        public DmcAxis Z1_Axis { get; }
        [MotionPath(Z待机位)]
        [MotionPath(Z取料位)]
        [MotionPath(Z飞拍位)]
        [MotionPath(Z撕膜位1)]
        [MotionPath(Z撕膜位2)]
        [MotionPath(Z放料位)]
        [MotionPath(Z_NG放料位)]
        [MotionPath(Z_压力测试起始位)]
        [MotionPath(Z_压力测试终止位)]
        public DmcAxis Z2_Axis { get; }
        [MotionPath(Z待机位)]
        [MotionPath(Z取料位)]
        [MotionPath(Z飞拍位)]
        [MotionPath(Z撕膜位1)]
        [MotionPath(Z撕膜位2)]
        [MotionPath(Z放料位)]
        [MotionPath(Z_NG放料位)]
        [MotionPath(Z_压力测试起始位)]
        [MotionPath(Z_压力测试终止位)]
        public DmcAxis Z3_Axis { get; }
        [MotionPath(Z待机位)]
        [MotionPath(Z取料位)]
        [MotionPath(Z飞拍位)]
        [MotionPath(Z撕膜位1)]
        [MotionPath(Z撕膜位2)]
        [MotionPath(Z放料位)]
        [MotionPath(Z_NG放料位)]
        [MotionPath(Z_压力测试起始位)]
        [MotionPath(Z_压力测试终止位)]
        public DmcAxis Z4_Axis { get; }
        [MotionPath(Z待机位)]
        [MotionPath(Z取料位)]
        [MotionPath(Z飞拍位)]
        [MotionPath(Z撕膜位1)]
        [MotionPath(Z撕膜位2)]
        [MotionPath(Z放料位)]
        [MotionPath(Z_NG放料位)]
        [MotionPath(Z_压力测试起始位)]
        [MotionPath(Z_压力测试终止位)]
        public DmcAxis Z5_Axis { get; }
        [MotionPath(Z待机位)]
        [MotionPath(Z取料位)]
        [MotionPath(Z飞拍位)]
        [MotionPath(Z撕膜位1)]
        [MotionPath(Z撕膜位2)]
        [MotionPath(Z放料位)]
        [MotionPath(Z_NG放料位)]
        [MotionPath(Z_压力测试起始位)]
        [MotionPath(Z_压力测试终止位)]
        public DmcAxis Z6_Axis { get; }
        [MotionPath(Z待机位)]
        [MotionPath(Z取料位)]
        [MotionPath(Z飞拍位)]
        [MotionPath(Z撕膜位1)]
        [MotionPath(Z撕膜位2)]
        [MotionPath(Z放料位)]
        [MotionPath(Z_NG放料位)]
        [MotionPath(Z_压力测试起始位)]
        [MotionPath(Z_压力测试终止位)]
        public DmcAxis Z7_Axis { get; }

        public List<DmcAxis> Z_Axises => [Z1_Axis, Z2_Axis, Z3_Axis, Z4_Axis, Z5_Axis, Z6_Axis, Z7_Axis];
        public List<DmcAxis> R_Axises => [R1_Axis, R2_Axis, R3_Axis, R4_Axis, R5_Axis, R6_Axis, R7_Axis];
        public List<Nozzle> Nozzles => [N_夹爪1吸嘴, N_夹爪2吸嘴, N_夹爪3吸嘴, N_夹爪4吸嘴, N_夹爪5吸嘴, N_夹爪6吸嘴, N_夹爪7吸嘴];
        public Nozzle N_夹爪1吸嘴 => Electronic.Default.Nozzle_夹爪1吸嘴;
        public Nozzle N_夹爪2吸嘴 => Electronic.Default.Nozzle_夹爪2吸嘴;
        public Nozzle N_夹爪3吸嘴 => Electronic.Default.Nozzle_夹爪3吸嘴;
        public Nozzle N_夹爪4吸嘴 => Electronic.Default.Nozzle_夹爪4吸嘴;
        public Nozzle N_夹爪5吸嘴 => Electronic.Default.Nozzle_夹爪5吸嘴;
        public Nozzle N_夹爪6吸嘴 => Electronic.Default.Nozzle_夹爪6吸嘴;
        public Nozzle N_夹爪7吸嘴 => Electronic.Default.Nozzle_夹爪7吸嘴;
        public CylinderEx C_无杆缸 => Electronic.Cylinder_NG下料无杆缸;
        public CylinderEx C_定位缸 => Electronic.Cylinder_NG下料抽屉定位气缸;
        public Feeder Feeder1 { get; set; }
        public Feeder Feeder2 { get; set; }
        #endregion

        #region 构造函数
        public BanYunStation(NGXiaLiao nGXiaLiao, FoxconnMES foxconnMES)
        {
            RetryCount = 0;
            this.InitalizeAlarms();
            NGXiaoLiao = nGXiaLiao;
            FoxconnMES = foxconnMES;
            LogGroup = LoggerCategory.RunningInfo;
            JiaZhuaBianJu_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(JiaZhuaBianJu_Axis), NoId = 5, Name = "夹爪变距伺服" };
            X_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(X_Axis), NoId = 6, Name = "搬运X轴", CanMove = IsFoolProofingZ_Axise };
            Y_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Y_Axis), NoId = 7, Name = "搬运Y轴", CanMove = IsFoolProofingZ_Axise };
            Camera_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Camera_Axis), NoId = 4, Name = "下相机轴" };
            Z1_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z1_Axis), NoId = 8, Name = "夹爪1_Z轴" };
            Z2_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z2_Axis), NoId = 10, Name = "夹爪2_Z轴" };
            Z3_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z3_Axis), NoId = 12, Name = "夹爪3_Z轴" };
            Z4_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z4_Axis), NoId = 14, Name = "夹爪4_Z轴" };
            Z5_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z5_Axis), NoId = 16, Name = "夹爪5_Z轴" };
            Z6_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z6_Axis), NoId = 18, Name = "夹爪6_Z轴" };
            Z7_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z7_Axis), NoId = 20, Name = "夹爪7_Z轴" };
            R1_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R1_Axis), NoId = 9, Name = "夹爪1_R轴" };
            R2_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R2_Axis), NoId = 11, Name = "夹爪2_R轴" };
            R3_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R3_Axis), NoId = 13, Name = "夹爪3_R轴" };
            R4_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R4_Axis), NoId = 15, Name = "夹爪4_R轴" };
            R5_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R5_Axis), NoId = 17, Name = "夹爪5_R轴" };
            R6_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R6_Axis), NoId = 19, Name = "夹爪6_R轴" };
            R7_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R7_Axis), NoId = 21, Name = "夹爪7_R轴" };
            Add(X_Axis, Y_Axis);
            Add(Camera_Axis, JiaZhuaBianJu_Axis);
            Add(Z1_Axis, Z2_Axis, Z3_Axis, Z4_Axis, Z5_Axis, Z6_Axis, Z7_Axis);
            Add(R1_Axis, R2_Axis, R3_Axis, R4_Axis, R5_Axis, R6_Axis, R7_Axis);
            Add(N_夹爪1吸嘴, N_夹爪2吸嘴, N_夹爪3吸嘴, N_夹爪4吸嘴, N_夹爪5吸嘴, N_夹爪6吸嘴, N_夹爪7吸嘴);
            Add(C_定位缸, C_无杆缸);
        }
        #endregion

        #region 初始流程
        public bool IsInitialized => _isInitialized;
        public async Task<bool> InitializeStation(CancellationToken cancellationToken)
        {

            try
            {
                OnStepChanged("初始化中");
                _isInitialized = false;
                LogInfo("初始化->[开始清零信号]");
                SignalPanel.Signal.BanYunCompleted = false;
                //var axies = GetAxes();
                //axies.ForEach(x => x.Reset());
                //axies.ForEach(x => x.ServoOn(true));
                //await Task.Delay(500);
                //LogInfo("初始化->[Z轴回原点...]");
                //await Parallel.ForEachAsync(Z_Axises, cancellationToken, async (x, t) =>
                //{
                //    LogInfo($"初始化->[{x.Name}回原开始]");
                //    if (x.Current < 1)
                //        await x.MoveDeltaAsync(2, null, t);
                //    LogInfo($"初始化->[{x.Name}回原步骤1]");
                //    await x.MoveOriginAsync(t);
                //    LogInfo($"初始化->[{x.Name}回原步骤2]");
                //    await x.MoveToAsync(Z待机位, t);
                //    LogInfo($"初始化->[{x.Name}回原结束]");
                //});
                LogInfo("初始化->[Z轴回原点...]");
                var stateOrigin = await ZMoveOrigin(cancellationToken);
                if (stateOrigin == false)
                {
                    var axies = Z_Axises;
                    axies.ForEach(x => x.Reset());
                    axies.ForEach(x => x.ServoOn(true));
                    axies.ForEach(async x => await x.PauseAsync(cancelToken: cancellationToken));
                    await Task.Delay(1000);
                    stateOrigin = await ZMoveOrigin(cancellationToken);
                }
                if (stateOrigin == false)//回原失败
                    return false;
                Status.ZAxisPositions = Z_Axises.Select(x => x.Current).ToArray();
                LogInfo("初始化->[X/Y/变距轴/相机轴回原点开始...]");
                await Parallel.ForEachAsync([Y_Axis, X_Axis, JiaZhuaBianJu_Axis, Camera_Axis], cancellationToken, async (x, t) => await x.MoveOriginAsync(t));
                LogInfo("初始化->[变距轴开始到张开位置]");
                await JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, cancellationToken);
                LogInfo("初始化->[R轴回原点]");
                await Parallel.ForEachAsync(R_Axises, cancellationToken, async (x, t) => await x.MoveOriginAsync(t));
                LogInfo("初始化->[X/Y/R轴移动到待机位]");
                await Parallel.ForEachAsync([.. R_Axises, X_Axis, Y_Axis], cancellationToken, async (x, t) => await x.MoveToAsync(待机位, t));
                var emptyNozzles = Status.NozzleStatus.Select(x => x == TrayPointStatus.Empty).ToList();
                var nozzels = Functions.SelectObjects(Nozzles, emptyNozzles);
                var task4 = new List<Task<bool>>();
                foreach (var item in nozzels)
                {
                    task4.Add(item.StopAndCheckAsync(cancellationToken, 3_000));
                }
                var bools4 = await Task.WhenAll(task4);
                if (bools4.Any(x => !x))
                {
                    LogError($"初始化->[吸嘴破真空失败!]");
                    return false;
                }
                if (Status.NozzleStatus.Any(x => x != TrayPointStatus.Empty))
                {
                    if (Step == BanYunStationRunStep.Step04_从料盘取料)
                    {
                        Step = BanYunStationRunStep.Step03_XYR移动取料位;
                    }
                    if (Step == BanYunStationRunStep.Step08_等待撕膜完成)
                    {
                        Step = BanYunStationRunStep.Step07_移动撕膜位;
                    }
                }
                else
                {
                    Step = BanYunStationRunStep.Step01_等待入料盘就绪;
                    LogInfo($"初始化->[等待入料盘到位信号]");
                }
                CurrentFeedTrayColChanged.SafeInvoke(this, Status.CurrentFeedTrayCol);
                OnStepChanged("初始化完成");
                _isInitialized = true;
                SaveRuningRecordStateInit();
                LogInfo("初始化完成");
            }
            catch (Exception ex)
            {
                _isInitialized = false;
                OnStepChanged("初始化失败");
                LogError($"初始化->[异常]{ex.Message}", ex);
            }
            return _isInitialized;
        }
        /// <summary>
        /// Z轴回原
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        async Task<bool> ZMoveOrigin(CancellationToken cancellationToken, int homeTimeout = 20_000)
        {
            List<bool> homeList = new List<bool>();
            await Parallel.ForEachAsync(Z_Axises, cancellationToken, async (x, t) =>
            {
                LogInfo($"初始化->[{x.Name}回原开始]");
                if (x.Current < 1)
                    await x.MoveDeltaAsync(2, null, t);
                LogInfo($"初始化->[{x.Name}回原步骤1]");
                var state = await x.MoveOriginAsync2(t, homeTimeout);
                homeList.Add(state);
                if (state)
                {
                    LogInfo($"初始化->[{x.Name}回原步骤2]");
                    await x.MoveToAsync(Z待机位, t);
                    LogInfo($"初始化->[{x.Name}回原结束]");
                }
                else
                {
                    LogInfo($"初始化->[{x.Name}回原Timeout]");
                }
            });
            return homeList.All(x => x == true) ? true : false;
        }

        #endregion

        #region 运行流程
        /// <summary>
        /// 运行步骤
        /// </summary>
        public BanYunStationRunStep Step
        {
            get => (BanYunStationRunStep)Status.Step;
            set
            {
                Status.Step = (int)value;
                Status.Save();
            }
        }
        int flyReadCodeCountUp = 1;
        int flyReadCodeCount = 1;
        protected override async Task PreRunning()
        {
            try
            {
                var axisList = GetAxes();
                foreach (var axis in axisList)
                {
                    await axis.InitializeAsync();
                }
                _inspectorOption = _optionRepository.Get<InspectorOption>();
                Status = RunningStatus.GetRecord<BanYunRunningStatus>("BanYun.json");
                Option = Recipe.Get<BanYunStationOption>(Id);
                if (_isInitialized == false)
                {
                    throw new Exception("未初始化");
                }
                else
                {
                    for (int i = 0; i < Z_Axises.Count; i++)
                    {
                        if (Math.Abs(Z_Axises[i].Current - Status.ZAxisPositions[i]) > 1)
                        {
                            await Z_Axises[i].MoveToAsync(Z待机位, CancellationToken);
                        }
                    }
                    await RecoverPreRunning();
                }
            }
            catch (Exception ex)
            {
                Root.Stop();
                LogError($"运行之前异常", ex);
            }
        }
        protected override async Task RunningCoreAsync()
        {
            await Step01_等待入料盘就绪();
            await Step02_上相机飞拍_读码();
            await Step14_上相机_MESLQ();
            await Step12_上相机_MES进站();
            await Step03_XYR移动取料位();
            await Step04_从料盘取料();
            await Step05_等待撕膜就绪();
            await Step06_下相机飞拍_对位();
            await Step14_下相机_MESLQ();
            await Step12_下相机_MES进站();
            await Step07_移动撕膜位();
            await Step08_等待撕膜完成();
            await Step09_下相机飞拍_复检();
            await Step13_MES出站();
            await Step10_放OK料();
            await Step11_放NG料();
        }
        protected override async void OnStopped()
        {
            var axies = GetAxes();
            await Parallel.ForEachAsync(axies, cancellationToken: default, async (x, t) => await x.PauseAsync());
            FeedTray.Instance.Save();
            SaveRuningRecordState();
        }
        async Task Step01_等待入料盘就绪()
        {
            if (Step != BanYunStationRunStep.Step01_等待入料盘就绪) return;
            OnStepChanged("Step01_等待入料盘就绪");
            LogInfo("Step01_等待入料盘就绪->[开始]");
            await Judger.Sure(() => SignalPanel.Signal.FeedTrayReady, CancellationToken);
            LogInfo("Step01_等待入料盘就绪->[结束]");
            Step = _inspectorOption.IsUseUpReadBarcode ? BanYunStationRunStep.Step02_上相机飞拍_读码 : BanYunStationRunStep.Step03_XYR移动取料位;
        }
        async Task Step02_上相机飞拍_读码()
        {
            // X===> -     +
            //       -
            // Y===>
            //       +
            if (_inspectorOption.IsUseUpReadBarcode == false) return;
            if (Step != BanYunStationRunStep.Step02_上相机飞拍_读码) return;
            OnStepChanged("Step02_上相机飞拍_读码");
            //判断当前列是否有料，无料继续判断下一列
            while (!IsCheckProductState())
            {
                LogInfo($"Step02_上相机飞拍_读码->[当前料盘列{CurrentFeedTrayCol}无产品]");
                CurrentFeedTrayCol = GetNextColumn(CurrentFeedTrayCol, out bool reverse, out bool isNewTray);
                LogInfo($"Step02_上相机飞拍_读码->[寻找下一料盘列{CurrentFeedTrayCol}]");
                if (isNewTray)
                {
                    LogInfo($"Step02_上相机飞拍_读码->[入料盘取料完成,XYZ到待机位->开始]");
                    await MoveXYToOriginal("Step02_上相机飞拍_读码");
                    SignalPanel.Signal.FeedTrayCompleted = true;
                    await Judger.Sure(() => SignalPanel.Signal.FeedTrayCompleted == false);
                    Step = BanYunStationRunStep.Step01_等待入料盘就绪;
                    LogInfo($"Step02_上相机飞拍_读码->[入料盘取料完成,XYZ到待机位->结束]");
                    return;
                }
            }
            LogInfo($"Step02_上相机飞拍_读码->[设置参数]");
            var colStatus = FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1];
            var destName = ProductDirection(CurrentFeedTrayCol) ? 上相机读码位1 : 上相机读码位2;
            var offsetX = GetFeedTrayOffset(CurrentFeedTrayCol);//X间隔的距离
            var speedX = X_Axis.GetVelocityCurve(destName);
            var destX = X_Axis.GetTargetPosition(destName) + offsetX;
            await Task.WhenAll(X_Axis.MoveToAsync(destX, speedX, CancellationToken), Y_Axis.MoveToAsync(destName, CancellationToken));
            var endPost = Y_Axis.Current + FeedTray.Instance.RowDistance * 7 + 10;//飞拍结束位，以最后结束位加10ms
            var offsetY1 = GetFeedTrayOffsetY(0) + 1;//防止第一个位置就触发取图
            var offsetY2 = GetFeedTrayOffsetY(1);
            var offsetY3 = GetFeedTrayOffsetY(2);
            var offsetY4 = GetFeedTrayOffsetY(3);
            var offsetY5 = GetFeedTrayOffsetY(4);
            var offsetY6 = GetFeedTrayOffsetY(5);
            var offsetY7 = GetFeedTrayOffsetY(6);
            //查找当前列那些产品需要飞拍的
            List<int> flyCaptureLists = new List<int>();
            bool[] hasProducts = new bool[colStatus.Items.Count()];
            for (int i = 0; i < colStatus.Items.Count(); i++)
            {
                hasProducts[i] = colStatus.Items[i].Status != TrayPointStatus.Empty ? true : false;
                if (colStatus.Items[i].Status != TrayPointStatus.Empty)
                {
                    int number = i + 1;
                    number = Math.Abs(number - 8);
                    flyCaptureLists.Add(number);
                }
            }
            LogInfo($"Step02_上相机飞拍_读码->[飞拍准备]");
            await Vision.PrepearUpFlyCapture(IsUseSiMo1, CurrentFeedTrayCol, flyCaptureLists, SignalPanel.Signal.CurrentFeedTray);
            SetFlyCapture2(new List<double> { offsetY1, offsetY2, offsetY3, offsetY4, offsetY5, offsetY6, offsetY7 });
            var velocityCurve = Y_Axis.GetVelocityCurve(destName);
            LogInfo($"Step02_上相机飞拍_读码->[飞拍开始]");
            await Y_Axis.MoveToAsync(endPost, velocityCurve, CancellationToken);
            LogInfo($"Step02_上相机飞拍_读码->[飞拍结束]");
            var (isSuccess, results) = await Vision.GetUpFlyCaptureResults_Funcation(hasProducts);
            barCodeLists.Clear();
            if (isSuccess)//读码成功的；直接赋值
            {
                for (int i = 0; i < results.Count(); i++)
                {
                    if (colStatus.Items[i].Status != TrayPointStatus.Empty)
                    {
                        colStatus.Items[i].Status = results[i].Quality == Quality.Ok ? TrayPointStatus.OK : TrayPointStatus.NG;
                        if (results[i].Quality == Quality.Ok)
                        {
                            barCodeLists.Add(results[i].Barcode);
                        }
                        else
                        {
                            barCodeLists.Add(string.Empty);
                        }
                    }
                    else
                    {
                        barCodeLists.Add(string.Empty);
                    }
                }
                FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1] = colStatus;
                flyReadCodeCountUp = 1;
                LogInfo($"Step02_上相机飞拍_读码->[飞拍成功]");
            }
            else
            {
                if (flyReadCodeCountUp >= _inspectorOption.FlyReadCodeCount)//当读码飞拍次数达到设定次数
                {
                    FlaySnapNGWraning = true;
                    for (int i = 0; i < results.Count(); i++)//根据实际结果来判断,但是如果本来列里面就没有产品就不判断了。
                    {
                        if (colStatus.Items[i].Status != TrayPointStatus.Empty)
                        {
                            colStatus.Items[i].Status = results[i].Quality == Quality.Ok ? TrayPointStatus.OK : TrayPointStatus.NG;
                            if (results[i].Quality == Quality.Ok)
                            {
                                barCodeLists.Add(results[i].Barcode);
                            }
                            else
                            {
                                barCodeLists.Add(string.Empty);
                            }
                        }
                        else
                        {
                            barCodeLists.Add(string.Empty);
                        }
                    }
                    flyReadCodeCountUp = 1;
                    FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1] = colStatus;
                    LogInfo($"Step02_上相机飞拍_读码->[飞拍失败]");
                }
                else
                {
                    flyReadCodeCountUp = flyReadCodeCountUp + 1;
                    Step = BanYunStationRunStep.Step02_上相机飞拍_读码;
                    LogInfo($"Step02_上相机飞拍_读码->[飞拍重试{flyReadCodeCountUp}次]");
                    return;
                }
            }
            Step = FoxconnMES.Option.IsUseStackLQ == false ? BanYunStationRunStep.Step03_XYR移动取料位 : BanYunStationRunStep.Step14_MESLQ;
        }
        async Task Step03_XYR移动取料位()
        {
            if (Step != BanYunStationRunStep.Step03_XYR移动取料位) return;
            OnStepChanged("Step03_XYR移动取料位");
            LogInfo($"Step03_XYR移动取料位->[开始]");
            if (_inspectorOption.IsDryRunMode == false)//正常模式需要判断料盘是否有料
            {
                while (!IsCheckProductState())
                {
                    LogInfo($"Step03_XYR移动取料位->[当前料盘列{CurrentFeedTrayCol}无产品]");
                    CurrentFeedTrayCol = GetNextColumn(CurrentFeedTrayCol, out bool reverse, out bool isNewTray);
                    LogInfo($"Step03_XYR移动取料位->[寻找下一料盘列{CurrentFeedTrayCol}]");
                    if (isNewTray)
                    {
                        LogInfo($"Step03_XYR移动取料位->[料盘取料完成,XYZ到待机位->开始]");
                        await MoveXYToOriginal("Step03_XYR移动取料位");
                        SignalPanel.Signal.FeedTrayCompleted = true;
                        await Judger.Sure(() => SignalPanel.Signal.FeedTrayCompleted == false);
                        LogInfo($"Step03_XYR移动取料位->[料盘取料完成,XYZ到待机位->结束]");
                        Step = BanYunStationRunStep.Step01_等待入料盘就绪;
                        return;
                    }
                }
            }
            var destName = ProductDirection(CurrentFeedTrayCol) ? XYR取料位1 : XYR取料位2;
            var offsetX = GetFeedTrayOffset(CurrentFeedTrayCol);
            var speedX = X_Axis.GetVelocityCurve(destName);
            var destX = X_Axis.GetTargetPosition(destName) + offsetX;
            var destY = Y_Axis.GetTargetPosition(destName);
            //var destX = X_Axis.GetTargetPosition(destName) + offsetX + SignalPanel.Signal.FeedTrayOffset.X;
            //var destY = Y_Axis.GetTargetPosition(destName) + SignalPanel.Signal.FeedTrayOffset.Y;
            var speedY = Y_Axis.GetVelocityCurve(destName);
            LogInfo($"Step03_XYR移动取料位->[XY轴移动到取料位,夹爪变距张开,R轴旋转]");
            var tasks = new List<Task>()
                {
                  X_Axis.MoveToAsync(destX, speedX, CancellationToken).ContinueWith(x => LogInfo($"Step03_XYR移动取料位->[{X_Axis.Name}已移动到取料位{destX:F6}]")),
                  Y_Axis.MoveToAsync(destY, speedY,CancellationToken).ContinueWith(x => LogInfo($"Step03_XYR移动取料位->[{Y_Axis.Name}已移动到取料位]")),
                };
            bool isRaxisNeedMove = R_Axises.Any(x => Math.Abs(x.Current - x.GetTargetPosition(destName)) > 0.1);
            if (isRaxisNeedMove)
            {
                tasks.Add(JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, CancellationToken).ContinueWith(x => LogInfo($"Step03_XYR移动取料位->{JiaZhuaBianJu_Axis.Name}变距已移动到张开位")));
            }
            await Task.WhenAll(tasks);
            if (isRaxisNeedMove)
            {
                LogInfo("Step03_XYR移动取料位->[R轴移动到取料位开始]");
                await Parallel.ForEachAsync(R_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(destName, t));
                LogInfo("Step03_XYR移动取料位->[R轴移动到取料位结束]");
            }
            LogInfo("Step03_XYR移动取料位->[夹爪变距到缩紧位开始]");
            await JiaZhuaBianJu_Axis.MoveToAsync(BJ_缩紧位, CancellationToken);
            LogInfo("Step03_XYR移动取料位->[夹爪变距到缩紧位结束]");
            Step = BanYunStationRunStep.Step04_从料盘取料;
            LogInfo($"Step03_XYR移动取料位->[结束]");
        }
        async Task Step04_从料盘取料()
        {
            if (Step != BanYunStationRunStep.Step04_从料盘取料) return;
            OnStepChanged("Step04_从料盘取料");
            LogInfo("Step04_从料盘取料->[开始]");
            var colStatus = FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1];
            if (_inspectorOption.IsDryRunMode)//空跑模式
            {
                Status.NozzleStatus = [TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK];
                OnNozzelProductChanged();
            }
            else
            {
                if (colStatus.Items.All(x => x.Status == TrayPointStatus.Empty || x.Status == TrayPointStatus.CompletedOK))
                {
                    LogInfo($"Step04_从料盘取料->[当前料盘列{CurrentFeedTrayCol}无产品]");
                    CurrentFeedTrayCol = GetNextColumn(CurrentFeedTrayCol, out bool reverse, out bool isNewTray);
                    if (isNewTray)
                    {
                        LogInfo("Step04_从料盘取料->[入料盘取料完成,XYZ到待机位->开始]");
                        await MoveXYToOriginal("Step04_从料盘取料");
                        if (!_inspectorOption.IsDryRunMode)
                        {
                            SignalPanel.Signal.FeedTrayCompleted = true;
                            await Judger.Sure(() => SignalPanel.Signal.FeedTrayCompleted == false);
                        }
                        LogInfo("Step04_从料盘取料->[入料盘取料完成,XYZ到待机位->结束]");
                        Step = BanYunStationRunStep.Step01_等待入料盘就绪;
                    }
                    return;
                }
                if (colStatus.RowCount != Status.NozzleStatus.Length)
                {
                    string error = $"Step04_从料盘取料->料盘行数{colStatus.RowCount}和吸嘴数量{Status.NozzleStatus.Length}不一致";
                    LogError(error);
                    throw new Exception(error);
                }
                for (int i = 0; i < colStatus.RowCount; i++)
                {
                    Status.NozzleStatus = colStatus.Items.Select(x => x.Status).ToArray();
                }
                OnNozzelProductChanged();
            }
            if (!_inspectorOption.IsDryRunMode)//正常模式,先提前吸真空
            {
                LogInfo("Step04_从料盘取料->[7个吸嘴吸真空开始]");
                var nozzles = Functions.SelectObjects(Nozzles, Status.NozzleStatus.Select(x => x == TrayPointStatus.OK || x == TrayPointStatus.NG).ToList());
                for (int i = 0; i < nozzles.Count(); i++)
                {
                    nozzles[i].SuckAsync();
                }
            }
            LogInfo("Step04_从料盘取料->[等待供料盘恢复标志完成]");
            await Judger.Sure(() => GongLiaoStation.RecoverPreStateFlag, CancellationToken);
            LogInfo("Step04_从料盘取料->[夹爪已变距到缩紧位,Z轴下降到取料位]");
            var z_axis = Functions.SelectObjects(Z_Axises, Status.NozzleStatus.Select(x => x == TrayPointStatus.OK || x == TrayPointStatus.NG).ToList());
            await Parallel.ForEachAsync(z_axis, CancellationToken, async (x, t) => await x.MoveToAsync(Z取料位, t));
            if (_inspectorOption.IsDryRunMode)//空跑模式
            {
                foreach (var item in Nozzles)
                {
                    item.SuckAsync();
                }
                await Task.Delay(200);
                foreach (var item in Nozzles)
                {
                    item.BrokenAsync();
                    await Task.Delay(100);
                    item.StopAsync();
                }
            }
            else//正常模式
            {
                LogInfo("Step04_从料盘取料->[7个吸嘴吸真空判读");
                var nozzles = Functions.SelectObjects(Nozzles, Status.NozzleStatus.Select(x => x == TrayPointStatus.OK || x == TrayPointStatus.NG).ToList());
                await Task.Delay(_inspectorOption.BYMotionTimeOption.SuckVacuoDelay);
                for (int i = 0; i < nozzles.Count(); i++)
                {
                    if (!nozzles[i].IsOn())
                    {
                        nozzles[i].IsSensorOnError = true;
                    }
                }
                if (nozzles.All(x => x.IsSensorOnError))
                {
                    LogError("Step04_从料盘取料->[吸嘴取产品真空报警");
                    await Task.Delay(500);
                    return;
                }
            }
            LogInfo("Step04_从料盘取料->[Z轴开始上升到飞拍位]");
            await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z飞拍位, t));
            Step = BanYunStationRunStep.Step05_等待撕膜就绪;
            LogInfo("Step04_从料盘取料->[结束]");
        }
        async Task Step05_等待撕膜就绪()
        {
            if (Step != BanYunStationRunStep.Step05_等待撕膜就绪) return;
            OnStepChanged("Step05_等待撕膜就绪");
            LogInfo("Step05_等待撕膜就绪->[开始]");
            if (await CheckVacuoError("Step05_等待撕膜就绪")) return;
            await Judger.Sure(() => SignalPanel.Signal.SiMoReady, CancellationToken);
            LogInfo("Step05_等待撕膜就绪->[结束]");
            Step = BanYunStationRunStep.Step06_下相机飞拍_对位;
        }
        async Task Step06_下相机飞拍_对位()
        {
            if (Step != BanYunStationRunStep.Step06_下相机飞拍_对位) return;
            OnStepChanged("Step06_下相机飞拍_对位");
            string p = IsUseSiMo1 ? X飞拍位1 : X飞拍位2;
            LogInfo("Step06_下相机飞拍_对位->[开始移动XY到飞拍位置,夹爪变距张开]");
            await Task.WhenAll(X_Axis.MoveToAsync(p, CancellationToken), Y_Axis.MoveToAsync(Y飞拍起始位, CancellationToken), Camera_Axis.MoveToAsync(p, CancellationToken), JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, CancellationToken));
            LogInfo("Step06_下相机飞拍_对位->[XY已移动到飞拍位置,R轴旋转到撕膜位]");
            string position = IsUseSiMo1 ? XYR撕膜位1 : XYR撕膜位2;
            CaptureFlag captureFlag = IsUseSiMo1 ? CaptureFlag.DuiWei_0 : CaptureFlag.DuiWei_1;
            await Parallel.ForEachAsync(R_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(position, CancellationToken));
            LogInfo("Step06_下相机飞拍_对位->[R轴已旋转到撕膜位,Y轴移动飞拍]");
            var flyCaptureLists = GetNozzleProductStateNumbers(true);
            await Vision.PrepearBottomFlyCapture2(captureFlag, IsUseSiMo1, CurrentFeedTrayCol, SignalPanel.Signal.CurrentFeedTray, flyCaptureLists);
            SetFlyCapture();
            await Y_Axis.MoveToAsync(position, CancellationToken);
            LogInfo("Step06_下相机飞拍_对位->[Y轴完成移动飞拍]");
            var hasProducts = Status.NozzleStatus.Select(x => x != TrayPointStatus.Empty && x != TrayPointStatus.NG).ToArray();
            var (isSuccess, results) = await Vision.GetBottomFlyCaptureResults1_Funcation(captureFlag, hasProducts);
            if (_inspectorOption.IsUseUpReadBarcode == false)//下相机读码
            {
                barCodeLists.Clear();
            }
            if (!isSuccess)//失败判断结果
            {
                if (!_inspectorOption.IsDryRunMode)//正常模式
                {
                    if (flyReadCodeCount >= _inspectorOption.FlyReadCodeCount)//当读码飞拍次数达到设定次数
                    {
                        FlaySnapNGWraning = true;
                        for (int i = 0; i < results.Count(); i++)//根据实际结果来判断,但是如果本来吸嘴上就没有产品就不判断了。
                        {
                            if (Status.NozzleStatus[i] != TrayPointStatus.Empty)
                            {
                                Status.NozzleStatus[i] = results[i].Quality == Quality.Ok ? TrayPointStatus.OK : TrayPointStatus.NG;
                                if (results[i].Quality == Quality.Ok)
                                {
                                    barCodeLists.Add(results[i].Barcode);
                                }
                                else
                                {
                                    barCodeLists.Add(string.Empty);
                                }
                            }
                            else
                            {
                                barCodeLists.Add(string.Empty);
                            }
                        }
                        flyReadCodeCount = 1;
                    }
                    else
                    {
                        flyReadCodeCount = flyReadCodeCount + 1;
                        Step = BanYunStationRunStep.Step06_下相机飞拍_对位;
                        return;
                    }
                }
            }
            else
            {
                for (int i = 0; i < results.Count(); i++)//添加缓存Barcode用于MES过站
                {
                    if (Status.NozzleStatus[i] != TrayPointStatus.Empty)
                    {
                        if (results[i].Quality == Quality.Ok)
                        {
                            barCodeLists.Add(results[i].Barcode);
                        }
                        else
                        {
                            barCodeLists.Add(string.Empty);
                        }
                    }
                    else
                    {
                        barCodeLists.Add(string.Empty);
                    }
                }
                flyReadCodeCount = 1;
            }
            if (_inspectorOption.IsDryRunMode)
            {
                LogWarning("Step06_下相机飞拍_对位->[空跑模式，忽略下相机一次飞拍结果!]");
                results = [new(), new(), new(), new(), new(), new(), new()];
            }
            var jawOffset = SignalPanel.Signal.IsUseSiMo1 ? _inspectorOption.JawOffset1 : _inspectorOption.JawOffset2;

            #region 因为算法失败 补偿值很大，为了避免夹爪超行程报警，补偿设置为0
            var offsetR1 = (results[0].Quality == Quality.Ok ? results[0].Offset.Angle + jawOffset.Offset1 : 0);
            var offsetR2 = (results[1].Quality == Quality.Ok ? results[1].Offset.Angle + jawOffset.Offset2 : 0);
            var offsetR3 = (results[2].Quality == Quality.Ok ? results[2].Offset.Angle + jawOffset.Offset3 : 0);
            var offsetR4 = (results[3].Quality == Quality.Ok ? results[3].Offset.Angle + jawOffset.Offset4 : 0);
            var offsetR5 = (results[4].Quality == Quality.Ok ? results[4].Offset.Angle + jawOffset.Offset5 : 0);
            var offsetR6 = (results[5].Quality == Quality.Ok ? results[5].Offset.Angle + jawOffset.Offset6 : 0);
            var offsetR7 = (results[6].Quality == Quality.Ok ? results[6].Offset.Angle + jawOffset.Offset7 : 0);
            var r1 = R1_Axis.GetTargetPosition(position) + offsetR1;
            var r2 = R2_Axis.GetTargetPosition(position) + offsetR2;
            var r3 = R3_Axis.GetTargetPosition(position) + offsetR3;
            var r4 = R4_Axis.GetTargetPosition(position) + offsetR4;
            var r5 = R5_Axis.GetTargetPosition(position) + offsetR5;
            var r6 = R6_Axis.GetTargetPosition(position) + offsetR6;
            var r7 = R7_Axis.GetTargetPosition(position) + offsetR7;
            List<double> targetList = new List<double>() { r1, r2, r3, r4, r5, r6, r7 };
            var offsetList = new List<double>() { offsetR1, offsetR2, offsetR3, offsetR4, offsetR5, offsetR6 };
            targetList = targetList.Select(x => Math.Round(x, 2)).ToList();
            offsetList = offsetList.Select(x => Math.Round(x, 2)).ToList();
            LogInfo($"Step06_下相机飞拍_对位->[R轴旋转目标位->[{string.Join("|", targetList)}]补偿值->[{string.Join("|", offsetList)}]]");
            //var r1 = R1_Axis.GetTargetPosition(position) + results[6].Offset.Angle;
            //var r2 = R2_Axis.GetTargetPosition(position) + results[5].Offset.Angle;
            //var r3 = R3_Axis.GetTargetPosition(position) + results[4].Offset.Angle;
            //var r4 = R4_Axis.GetTargetPosition(position) + results[3].Offset.Angle;
            //var r5 = R5_Axis.GetTargetPosition(position) + results[2].Offset.Angle;
            //var r6 = R6_Axis.GetTargetPosition(position) + results[1].Offset.Angle;
            //var r7 = R7_Axis.GetTargetPosition(position) + results[0].Offset.Angle;
            #endregion

            #region TODO:因为算法失败 补偿值很大，为了避免夹爪超行程报警，补偿设置为0
            //SignalPanel.Signal.JawOffsets = results.Select(x => x.Offset.X).ToArray();
            SignalPanel.Signal.JawOffsets = results.Select(x => (x.Quality == Quality.Ok) ? x.Offset.X : 0).ToArray();
            #endregion
            var speed1 = R1_Axis.GetVelocityCurve(position);
            var speed2 = R2_Axis.GetVelocityCurve(position);
            var speed3 = R3_Axis.GetVelocityCurve(position);
            var speed4 = R4_Axis.GetVelocityCurve(position);
            var speed5 = R5_Axis.GetVelocityCurve(position);
            var speed6 = R6_Axis.GetVelocityCurve(position);
            var speed7 = R7_Axis.GetVelocityCurve(position);

            await Parallel.ForEachAsync([(R1_Axis, r1, speed1), (R2_Axis, r2, speed2), (R3_Axis, r3, speed3), (R4_Axis, r4, speed4), (R5_Axis, r5, speed5), (R6_Axis, r6, speed6), (R7_Axis, r7, speed7)], CancellationToken, async (x, t) => await x.Item1.MoveToAsync(x.Item2, x.Item3, t));
            Step = FoxconnMES.Option.IsUseStackIn == false ? BanYunStationRunStep.Step07_移动撕膜位 : BanYunStationRunStep.Step14_MESLQ;
            LogInfo("Step06_下相机飞拍_对位->[R轴旋转偏移完成]");
        }
        async Task Step07_移动撕膜位()
        {
            if (Step != BanYunStationRunStep.Step07_移动撕膜位) return;
            OnStepChanged("Step07_移动撕膜位");
            LogInfo("Step07_移动撕膜位->[开始]");
            var JudgerFeeder = IsUseSiMo1 ? Feeder1 : Feeder2;
            await Judger.Sure(() => JudgerFeeder.Axis.IsDone, CancellationToken);//等待飞达移动完成
            if (!JudgerFeeder.CheckIsReady())//检测飞达未就绪
            {
                SignalPanel.Signal.FeedrNotReady = true;
                LogInfo($"Step07_移动撕膜位->[{JudgerFeeder.Name}未就绪]");
                await Judger.Sure(() => SignalPanel.Signal.FeedrReadyDone);
                SignalPanel.Signal.FeedrNotReady = false;
                Step = BanYunStationRunStep.Step06_下相机飞拍_对位;//回到第一次飞拍起始位，重新飞拍
                LogInfo($"Step07_移动撕膜位->[移动回->Step06_下相机飞拍_对位->起始位]");
                return;
            }
            LogInfo($"Step07_移动撕膜位->[X轴开始移动到撕膜位置]");
            string ps = IsUseSiMo1 ? XYR撕膜位1 : XYR撕膜位2;
            await Parallel.ForEachAsync([X_Axis, Y_Axis], CancellationToken, async (x, t) => await x.MoveToAsync(ps, t));
            LogInfo($"Step07_移动撕膜位->[Z轴下降到撕膜位置]");
            var axis = Functions.SelectObjects(Z_Axises, Status.NozzleStatus.Select(x => x == TrayPointStatus.OK).ToList());
            await Parallel.ForEachAsync(axis, CancellationToken, async (x, t) => await x.MoveToAsync(IsUseSiMo1 ? Z撕膜位1 : Z撕膜位2, t));
            LogInfo($"Step07_移动撕膜位->[夹爪力矩值读值]");
            _ = CalcLiJu("Step07_移动撕膜位");
            SignalPanel.Signal.BanYunCompleted = true;
            Step = BanYunStationRunStep.Step08_等待撕膜完成;
            LogInfo($"Step07_移动撕膜位->[通知撕膜组件搬运完成]");
        }
        async Task Step08_等待撕膜完成()
        {
            if (Step != BanYunStationRunStep.Step08_等待撕膜完成) return;
            OnStepChanged("Step08_等待撕膜完成");
            LogInfo($"Step08_等待撕膜完成->[开始]");
            await Judger.Sure(() => SignalPanel.Signal.SiMoCompleted, CancellationToken, interval: 20);
            await Task.Delay(10);
            SignalPanel.Signal.BanYunCompleted = false;
            SignalPanel.Signal.SiMoCompleted = false;
            LogInfo($"Step08_等待撕膜完成->[结束]");
            Step = BanYunStationRunStep.Step09_下相机飞拍_复检;
        }
        async Task Step09_下相机飞拍_复检()
        {
            if (Step != BanYunStationRunStep.Step09_下相机飞拍_复检) return;
            OnStepChanged("Step09_下相机飞拍_复检");
            if (await CheckVacuoError("Step09_下相机飞拍_复检")) return;
            LogInfo("Step09_下相机飞拍_复检->[Z轴移动夹爪到飞拍位]");
            await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z飞拍位, t));
            if (await CheckVacuoError("Step09_下相机飞拍_复检")) return;
            string ps = IsUseSiMo1 ? X飞拍位1 : X飞拍位2;
            string ps2 = IsUseSiMo1 ? XYR撕膜位1 : XYR撕膜位2;
            LogInfo("Step09_下相机飞拍_复检->[Z轴已到飞拍位,XY轴开始移动下相机飞拍_复检位置]");
            await Task.WhenAll(X_Axis.MoveToAsync(ps, CancellationToken), Y_Axis.MoveToAsync(ps2, CancellationToken));
            LogInfo("Step09_下相机飞拍_复检->[XY轴已到飞拍位置,开始飞拍]");
            SetFlyCapture();
            CaptureFlag captureFlag = IsUseSiMo1 ? CaptureFlag.Detect_1 : CaptureFlag.Detect_1;
            var flyCaptureLists = GetNozzleProductStateNumbers();
            await Vision.PrepearBottomFlyCapture2(captureFlag, IsUseSiMo1, CurrentFeedTrayCol, SignalPanel.Signal.CurrentFeedTray, flyCaptureLists);
            LogInfo("Step09_下相机飞拍_复检->[飞拍开始]");
            await Y_Axis.MoveToAsync(Y飞拍起始位, CancellationToken);
            LogInfo("Step09_下相机飞拍_复检->[飞拍结束]");
            var hasProducts = Status.NozzleStatus.Select(x => x != TrayPointStatus.Empty && x != TrayPointStatus.NG).ToArray();
            var (isSuccess, results) = await Vision.GetBottomFlyCaptureResults2_Funcation(captureFlag, hasProducts);
            if (!isSuccess && !_inspectorOption.IsDryRunMode)
            {
                LogError("Step09_下相机飞拍_复检->[算法失败]");
            }
            if (_inspectorOption.IsDryRunMode)//空跑模式
            {
                for (int i = 0; i < results.Length; i++)
                {
                    if (Status.NozzleStatus[i] != TrayPointStatus.Empty)
                        Status.NozzleStatus[i] = TrayPointStatus.CompletedOK;
                }
            }
            else
            {
                for (int i = 0; i < results.Length; i++)
                {
                    #region TODO 撕膜NG和无产品都不进行撕膜复检结果判断
                    if (Status.NozzleStatus[i] != TrayPointStatus.Empty && Status.NozzleStatus[i] != TrayPointStatus.NG)
                    {
                        Status.NozzleStatus[i] = results[i] ? TrayPointStatus.CompletedOK : TrayPointStatus.CompletedNG;
                    }
                    #endregion
                }
            }
            LogInfo("Step09_下相机飞拍_复检->[R轴到放料位]");
            var destName = ProductDirection(CurrentFeedTrayCol) ? XYR取料位1 : XYR取料位2;
            await Parallel.ForEachAsync(R_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(destName, t));
            LogInfo("Step09_下相机飞拍_复检->[结束]");
            Step = FoxconnMES.Option.IsUseStackOut == false ? BanYunStationRunStep.Step10_放OK料 : BanYunStationRunStep.Step13_MES出站;
        }
        async Task Step10_放OK料()
        {
            if (Step != BanYunStationRunStep.Step10_放OK料) return;
            var dataStorageService = Service.GetService<IDataStorageService>();
            OnStepChanged("Step10_放OK料");
            if (GongLiaoStation.IsProuductRegistered)
            {
                LogInfo("Step10_放OK料->[开始]");
                List<DmcAxis> axises = Functions.SelectObjects(Z_Axises, Status.NozzleStatus.Select(x => x == TrayPointStatus.CompletedOK).ToList());
                LogInfo("Step10_放OK料->[Z轴移动到飞拍位安全位开始]");
                await Parallel.ForEachAsync(axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z飞拍位, t));
                LogInfo("Step10_放OK料->[Z轴移动到飞拍位安全位结束]");
                var destName = ProductDirection(CurrentFeedTrayCol) ? XYR取料位1 : XYR取料位2;
                var offsetX = GetFeedTrayOffset(CurrentFeedTrayCol);
                var speedX = X_Axis.GetVelocityCurve(destName);
                var destX = X_Axis.GetTargetPosition(destName) + offsetX;
                LogInfo("Step10_放OK料->[X/Y轴开始移动到放料位,变距缩紧]");
                if (!IsFoolProofingZ_Axise())
                    await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z飞拍位, t));
                await Task.WhenAll(
                   X_Axis.MoveToAsync(destX, speedX, CancellationToken)
                   .ContinueWith(x => LogInfo($"Step10_放OK料->{X_Axis.Name}X已移动到放料位[{destX:F6}]")),
                   Y_Axis.MoveToAsync(destName, CancellationToken)
                   .ContinueWith(x => LogInfo($"Step10_放OK料->{Y_Axis.Name}Y已移动到放料位")),
                   JiaZhuaBianJu_Axis.MoveToAsync(BJ_缩紧位, CancellationToken).ContinueWith(x => LogInfo($"Step10_放OK料->{JiaZhuaBianJu_Axis.Name}已移动到缩紧位"))
                   );
                LogInfo("Step10_放OK料->[等待供料盘恢复标志完成]");
                await Judger.Sure(() => GongLiaoStation.RecoverPreStateFlag, CancellationToken);
                LogInfo("Step10_放OK料->[X/Y/变距已到放料位,Z轴下降到放料位]");
                await Parallel.ForEachAsync(axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z放料位, t));
                List<Nozzle> nozzles = Functions.SelectObjects(Nozzles, Status.NozzleStatus.Select(x => x == TrayPointStatus.CompletedOK).ToList());
                LogInfo("Step10_放OK料->[Z轴已下降到放料位,开始破真空]");
                await Parallel.ForEachAsync(nozzles, CancellationToken, async (x, t) => await x.BrokenAndCheckAsync(CancellationToken));
                var nozzleStatus = Status.NozzleStatus.ToList();
                _ = Task.Run(() => dataStorageService.SaveDataCsv(nozzleStatus.ToArray()));
                for (int i = 0; i < Status.NozzleStatus.Length; i++)
                {
                    if (Status.NozzleStatus[i] == TrayPointStatus.CompletedOK)
                    {
                        Status.NozzleStatus[i] = TrayPointStatus.Empty;
                        FeedTray.Instance.SetTrayPointStatus(CurrentFeedTrayCol, i + 1, TrayPointStatus.CompletedOK);
                    }
                }
                OnNozzelProductChanged();
                int okCount = nozzles.Count;
                ProductCompleted?.SafeInvoke(this, (true, okCount));
                LogInfo("Step10_放OK料->[Z轴到待机位置,停止破真空]");
                await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(待机位, t));
                for (int i = 0; i < nozzles.Count(); i++)
                {
                    nozzles[i].StopAsync();
                }
                LogInfo("Step10_放OK料->[结束]");
            }
            else
            {
                LogInfo("Step10_放OK料->[产品不在籍]");
                for (int i = 0; i < 7; i++)
                {
                    if (Status.NozzleStatus[i] != TrayPointStatus.Empty)
                    {
                        Status.NozzleStatus[i] = TrayPointStatus.CompletedNG;
                    }
                }
                var nozzleStatus = Status.NozzleStatus.ToList();
                _ = Task.Run(() => dataStorageService.SaveDataCsv(nozzleStatus.ToArray()));
                OnNozzelProductChanged();
                LogInfo("Step10_放OK料->[产品不在籍强制NG]");
            }

            Step = BanYunStationRunStep.Step11_放NG料;
        }
        async Task Step11_放NG料()
        {
            if (Step != BanYunStationRunStep.Step11_放NG料) return;
            OnStepChanged("Step11_放NG料");
            LogInfo("Step11_放NG料->[开始]");
            bool hasNG = Status.NozzleStatus.Any(x => x == TrayPointStatus.CompletedNG || x == TrayPointStatus.NG);
            if (hasNG)
            {
                LogInfo("Step11_放NG料->[移动待机开始]");
                await MoveXYToOriginal("Step11_放NG料_1");
                LogInfo("Step11_放NG料->[移动待机结束]");
                for (int i = 0; i < Status.NozzleStatus.Length; i++)
                {
                    bool isNG = Status.NozzleStatus[i] == TrayPointStatus.CompletedNG || Status.NozzleStatus[i] == TrayPointStatus.NG;
                    if (isNG)
                    {
                        if (!NGXiaoLiao.CheckIsTrayReady())
                        {
                            NGTrayNoReadyError = true;
                            LogError("Step11_放NG料->[NG料盘未就绪]");
                            await Task.Delay(1000);
                            return;
                        }
                        var nozzele = Nozzles[i];
                        var zaxis = Z_Axises[i];
                        int minRow = 1;
                        int maxCol = 3;
                        //var item = NGTray.Instance.GetNext2(minRow, maxCol);
                        var item = NGTray.Instance.GetNext3(minRow, maxCol);
                        if (item == null)
                        {
                            if (_inspectorOption.IsDryRunMode)
                            {
                                NGTray.Instance.Reset();
                                //item = NGTray.Instance.GetNext2(minRow, maxCol);
                                item = NGTray.Instance.GetNext3(minRow, maxCol);
                            }
                            else
                            {
                                NGTrayFullError = true;
                                await Task.Delay(500);
                                return;
                            }
                        }
                        var (PointX, PointY) = item.GetPutPoint(X_Axis.GetTargetPosition(XY_NG下料位), Y_Axis.GetTargetPosition(XY_NG下料位));
                        var x = PointX;
                        var y = PointY + (i * _inspectorOption.JawDistance);
                        var speedx = X_Axis.GetVelocityCurve(XY_NG下料位);
                        var speedy = Y_Axis.GetVelocityCurve(XY_NG下料位);
                        if (x > X_Axis.GetTargetPosition(XY_NG下料避让位) && y > Y_Axis.GetTargetPosition(XY_NG下料避让位))
                        {
                            XYUnloadNGError = true;
                            LogError("Step11_放NG料->[XY到放料NG点超限位,可能发生碰撞,请检查XY轴的NG下料避让点位设置]");
                            await Task.Delay(2000);
                            return;
                        }
                        LogInfo("Step11_放NG料->[XY轴移动到放料NG点]");
                        await Task.WhenAll(Y_Axis.MoveToAsync(y, speedy, CancellationToken), X_Axis.MoveToAsync(x, speedx, CancellationToken));
                        LogInfo("Step11_放NG料->[X/Y/已到NG放料位,R轴到NG放料位]");
                        await Parallel.ForEachAsync(R_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(R_NG放料位, t));
                        LogInfo("Step11_放NG料->[X/Y/R轴已到NG放料位,Z轴移动到放料NG点]");
                        await zaxis.MoveToAsync(Z_NG放料位, CancellationToken);
                        LogInfo("Step11_放NG料->[Z轴已到放料NG点,吸嘴破真空]");
                        nozzele.BrokenAsync();
                        item.Put();
                        await Task.Delay(200);
                        if (!await nozzele.StopAndCheckAsync() && !_inspectorOption.IsDryRunMode)
                        {
                            LogError("Step11_放NG料->[吸嘴破真空失败]");
                            await Task.Delay(500);
                            return;
                        }
                        LogInfo("Step11_放NG料->[Z轴移动到放料待机位开始]");
                        await zaxis.MoveToAsync(Z待机位, CancellationToken);
                        Status.NozzleStatus[i] = TrayPointStatus.Empty;
                        FeedTray.Instance.SetTrayPointStatus(CurrentFeedTrayCol, i + 1, TrayPointStatus.Empty);
                        NGTray.Instance.OnNGTrayItemStatusChanged(item.Row, item.Col, TrayPointStatus.CompletedNG);
                        ProductCompleted?.SafeInvoke(this, (false, 1));
                        LogInfo("Step11_放NG料->[Z轴移动到放料待机位结束]");
                    }
                }
            }
            CurrentFeedTrayCol = GetNextColumn(CurrentFeedTrayCol, out bool reverse, out bool isNewTray);
            if (isNewTray)
            {
                LogInfo("Step11_放NG料->[入料盘取料完成,XYZ到待机位->开始]");
                await MoveXYToOriginal("Step11_放NG料_2");
                if (!_inspectorOption.IsDryRunMode)//正常模式
                {
                    SignalPanel.Signal.FeedTrayCompleted = true;
                    await Judger.Sure(() => SignalPanel.Signal.FeedTrayCompleted == false);
                }
                LogInfo("Step11_放NG料->[入料盘取料完成,XYZ到待机位->结束]");
            }
            Step = BanYunStationRunStep.Step01_等待入料盘就绪;
        }
        /// <summary>
        /// 缓存键值0代表无产品,1=代表有产品
        /// </summary>
        List<string> barCodeLists = new List<string>();
        FoxconnMES FoxconnMES { get; set; }
        /// <summary>
        /// 人工确认
        /// </summary>
        public event Func<string, Task<bool>> ManualMESConfirmChanged;
        async Task Step12_上相机_MES进站()
        {
            if (_inspectorOption.IsUseUpReadBarcode)
            {
                await Step12_MES进站("Step12_上相机_MES进站");
            }
        }
        async Task Step12_下相机_MES进站()
        {
            if (_inspectorOption.IsUseUpReadBarcode == false)
            {
                await Step12_MES进站("Step12_下相机_MES进站");
            }
        }
        async Task Step14_上相机_MESLQ()
        {
            if (_inspectorOption.IsUseUpReadBarcode)
            {
                await Step14_MESLQ();
            }
        }
        async Task Step14_下相机_MESLQ()
        {
            if (_inspectorOption.IsUseUpReadBarcode == false)
            {
                await Step14_MESLQ();
            }
        }
        async Task Step12_MES进站(string name)
        {
            if (Step != BanYunStationRunStep.Step12_MES进站) return;
            OnStepChanged($"{name}");
            LogInfo($"{name}->[开始]");
            if (FoxconnMES.Option.IsUseStackIn)
            {
                var colStatus = FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1];
                var mesResult = await FoxconnMES.StackIn(barCodeLists.ToArray());
                if (mesResult.GetQuality() == Quality.Ok)
                {
                    LogInfo($"{name}->[成功]");
                }
                else
                {
                    LogInfo($"{name}->[失败]");
                    string message = "MES进站:\r\n";
                    foreach (var itemData in mesResult.ItemDatas)
                    {
                        if (itemData != null && itemData.IsBarcode)
                        {
                            message += $"{itemData.Barcode}{itemData.Quality.ToString().ToUpper()}\r\n";
                        }
                    }
                    var state = await ManualMESConfirm(message);
                    if (state)
                    {
                        await Task.Delay(1000);
                        LogInfo($"{name}-重试");
                        return;
                    }
                    else
                    {
                        for (int i = 0; i < mesResult.ItemDatas.Count(); i++)//根据实际结果来判断,但是如果本来列里面就没有产品就不判断了。
                        {
                            if (colStatus.Items[i].Status != TrayPointStatus.Empty)
                            {
                                colStatus.Items[i].Status = mesResult.ItemDatas[i].Quality == Quality.Ok ? TrayPointStatus.OK : TrayPointStatus.NG;
                            }
                        }
                        FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1] = colStatus;
                        LogInfo($"{name}-跳过");
                    }
                }
            }
            else
            {
                LogInfo($"{name}->[未开启]");
            }
            Step = _inspectorOption.IsUseUpReadBarcode ? BanYunStationRunStep.Step03_XYR移动取料位 : BanYunStationRunStep.Step07_移动撕膜位;
        }
        async Task Step14_MESLQ()
        {
            string name = "MESLQ";
            if (Step != BanYunStationRunStep.Step14_MESLQ) return;
            OnStepChanged($"{name}");
            LogInfo($"{name}->[开始]");
            if (FoxconnMES.Option.IsUseStackLQ)
            {
                var colStatus = FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1];
                var mesResult = await FoxconnMES.StackLQ(barCodeLists.ToArray());
                if (mesResult.GetQuality() == Quality.Ok)
                {
                    LogInfo($"{name}->[成功]");
                }
                else
                {
                    LogInfo($"{name}->[失败]");
                    string message = "MES进站:\r\n";
                    foreach (var itemData in mesResult.ItemDatas)
                    {
                        if (itemData != null && itemData.IsBarcode)
                        {
                            message += $"{itemData.Barcode}{itemData.Quality.ToString().ToUpper()}\r\n";
                        }
                    }
                    var state = await ManualMESConfirm(message);
                    if (state)
                    {
                        await Task.Delay(1000);
                        LogInfo($"{name}-重试");
                        return;
                    }
                    else
                    {
                        for (int i = 0; i < mesResult.ItemDatas.Count(); i++)//根据实际结果来判断,但是如果本来列里面就没有产品就不判断了。
                        {
                            if (colStatus.Items[i].Status != TrayPointStatus.Empty)
                            {
                                colStatus.Items[i].Status = mesResult.ItemDatas[i].Quality == Quality.Ok ? TrayPointStatus.OK : TrayPointStatus.NG;
                            }
                        }
                        FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1] = colStatus;
                        LogInfo($"{name}-跳过");
                    }
                }
            }
            else
            {
                LogInfo($"{name}->[未开启]");
            }
            Step = BanYunStationRunStep.Step12_MES进站;
        }
        async Task Step13_MES出站()
        {
            if (Step != BanYunStationRunStep.Step13_MES出站) return;
            OnStepChanged("Step13_MES出站");
            LogInfo("Step13_MES出站->[开始]");
            if (FoxconnMES.Option.IsUseStackOut)
            {
                var colStatus = FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1];
                var mesResult = await FoxconnMES.StackOut(barCodeLists.ToArray());
                if (mesResult.GetQuality() == Quality.Ok)
                {
                    LogInfo("Step13_MES出站->[成功]");
                }
                else
                {
                    LogInfo("Step13_MES出站->[失败]");
                    string message = "MES出站:\r\n";
                    foreach (var itemData in mesResult.ItemDatas)
                    {
                        if (itemData != null && itemData.IsBarcode)
                        {
                            message += $"{itemData.Barcode}{itemData.Quality.ToString().ToUpper()}\r\n";
                        }
                    }
                    var state = await ManualMESConfirm(message);
                    if (state)
                    {
                        await Task.Delay(1000);
                        LogInfo("Step13_MES出站-重试");
                        return;
                    }
                    else
                    {
                        for (int i = 0; i < mesResult.ItemDatas.Count(); i++)//根据实际结果来判断,但是如果本来列里面就没有产品就不判断了。
                        {
                            if (colStatus.Items[i].Status != TrayPointStatus.Empty)
                            {
                                colStatus.Items[i].Status = mesResult.ItemDatas[i].Quality == Quality.Ok ? TrayPointStatus.CompletedOK : TrayPointStatus.CompletedNG;
                            }
                        }
                        FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1] = colStatus;
                        LogInfo("Step13_MES出站-跳过");
                    }
                }
            }
            else
            {
                LogInfo("Step13_MES出站->[未开启]");
            }
            Step = BanYunStationRunStep.Step10_放OK料;
        }
        public async Task<bool> ManualMESConfirm(string message)
        {
            return await ManualMESConfirmChanged.Invoke(message);
        }
        public async Task Step11_放NG料_测试()
        {
            //if (Step != BanYunStationRunStep.Step11_放NG料) return;
            OnStepChanged("Step11_放NG料");
            LogInfo("Step11_放NG料->[开始]");
            Status.NozzleStatus = new TrayPointStatus[] { TrayPointStatus.CompletedNG, TrayPointStatus.CompletedNG, TrayPointStatus.CompletedNG, TrayPointStatus.CompletedNG, TrayPointStatus.CompletedNG, TrayPointStatus.CompletedNG, TrayPointStatus.CompletedNG };
            bool hasNG = Status.NozzleStatus.Any(x => x == TrayPointStatus.CompletedNG || x == TrayPointStatus.NG);
            if (hasNG)
            {
                LogInfo("Step11_放NG料->[移动待机开始]");
                //await MoveXYToOriginal("Step11_放NG料_1");
                LogInfo("Step11_放NG料->[移动待机结束]");
                for (int i = 0; i < Status.NozzleStatus.Length; i++)
                {
                    bool isNG = Status.NozzleStatus[i] == TrayPointStatus.CompletedNG || Status.NozzleStatus[i] == TrayPointStatus.NG;
                    if (isNG)
                    {
                        //if (!NGXiaoLiao.CheckIsTrayReady())
                        //{
                        //    NGTrayNoReadyError = true;
                        //    LogError("Step11_放NG料->[NG料盘未就绪]");
                        //    await Task.Delay(1000);
                        //    return;
                        //}
                        //var nozzele = Nozzles[i];
                        //var zaxis = Z_Axises[i];
                        int minRow = 1;
                        int maxCol = 3;
                        var item = NGTray.Instance.GetNext3(minRow, maxCol);
                        //if (item == null)
                        //{
                        //    if (_inspectorOption.IsDryRunMode)
                        //    {
                        //        NGTray.Instance.Reset();
                        //        item = NGTray.Instance.GetNext2(minRow, maxCol);
                        //    }
                        //    else
                        //    {
                        //        NGTrayFullError = true;
                        //        await Task.Delay(500);
                        //        return;
                        //    }
                        //}
                        var (PointX, PointY) = item.GetPutPoint(X_Axis.GetTargetPosition(XY_NG下料位), Y_Axis.GetTargetPosition(XY_NG下料位));
                        var x = PointX;
                        var y = PointY + (i * _inspectorOption.JawDistance);
                        Debug.WriteLine($"{item.Index}-x{PointX}-y{PointY}");
                        //var speedx = X_Axis.GetVelocityCurve(XY_NG下料位);
                        //var speedy = Y_Axis.GetVelocityCurve(XY_NG下料位);
                        //if (x > X_Axis.GetTargetPosition(XY_NG下料避让位) && y > Y_Axis.GetTargetPosition(XY_NG下料避让位))
                        //{
                        //    XYUnloadNGError = true;
                        //    LogError("Step11_放NG料->[XY到放料NG点超限位,可能发生碰撞,请检查XY轴的NG下料避让点位设置]");
                        //    await Task.Delay(2000);
                        //    return;
                        //}
                        // LogInfo("Step11_放NG料->[XY轴移动到放料NG点]");
                        //await Task.WhenAll(Y_Axis.MoveToAsync(y, speedy, CancellationToken), X_Axis.MoveToAsync(x, speedx, CancellationToken));
                        // LogInfo("Step11_放NG料->[X/Y/已到NG放料位,R轴到NG放料位]");
                        //await Parallel.ForEachAsync(R_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(R_NG放料位, t));
                        // LogInfo("Step11_放NG料->[X/Y/R轴已到NG放料位,Z轴移动到放料NG点]");
                        //await zaxis.MoveToAsync(Z_NG放料位, CancellationToken);
                        // LogInfo("Step11_放NG料->[Z轴已到放料NG点,吸嘴破真空]");
                        ///nozzele.BrokenAsync();
                        item.Put();
                        await Task.Delay(200);
                        //if (!await nozzele.StopAndCheckAsync() && !_inspectorOption.IsDryRunMode)
                        //{
                        //    LogError("Step11_放NG料->[吸嘴破真空失败]");
                        //    await Task.Delay(500);
                        //    return;
                        //}
                        //LogInfo("Step11_放NG料->[Z轴移动到放料待机位开始]");
                        //await zaxis.MoveToAsync(Z待机位, CancellationToken);
                        Status.NozzleStatus[i] = TrayPointStatus.Empty;
                        FeedTray.Instance.SetTrayPointStatus(CurrentFeedTrayCol, i + 1, TrayPointStatus.Empty);
                        NGTray.Instance.OnNGTrayItemStatusChanged(item.Row, item.Col, TrayPointStatus.CompletedNG);
                        ProductCompleted?.SafeInvoke(this, (false, 1));
                        LogInfo("Step11_放NG料->[Z轴移动到放料待机位结束]");
                    }
                }
            }
            CurrentFeedTrayCol = GetNextColumn(CurrentFeedTrayCol, out bool reverse, out bool isNewTray);
            //if (isNewTray)
            //{
            //    LogInfo("Step11_放NG料->[入料盘取料完成,XYZ到待机位->开始]");
            //    await MoveXYToOriginal("Step11_放NG料_2");
            //    if (!_inspectorOption.IsDryRunMode)//正常模式
            //    {
            //        SignalPanel.Signal.FeedTrayCompleted = true;
            //        await Judger.Sure(() => SignalPanel.Signal.FeedTrayCompleted == false);
            //    }
            //    LogInfo("Step11_放NG料->[入料盘取料完成,XYZ到待机位->结束]");
            //}
            //Step = BanYunStationRunStep.Step01_等待入料盘就绪;
        }
        #endregion

        #region 状态恢复流程
        BanYunRunningStatus _preRunStatus;
        /// <summary>
        /// 状态恢复流程异常
        /// </summary>
        bool _isRecoverPreRunningError = false;
        /// <summary>
        /// 复到到停止运行之前检测状态
        /// </summary>
        /// <returns></returns>
        protected async Task RecoverPreRunning()
        {
            try
            {
                LogInfo($"运行状态恢复->[开始]");
                _isRecoverPreRunningError = false;
                _preRunStatus = Status.Clone();
                if (!Camera_Axis.CheckIsInPosition(Status.CameraAxisPositions))//判断下相机X轴是否需要移动
                    await Camera_Axis.MoveToAsync(Status.CameraAxisPositions);
                if (!JiaZhuaBianJu_Axis.CheckIsInPosition(Status.BJAxisPositions))
                    await JiaZhuaBianJu_Axis.MoveToAsync(Status.BJAxisPositions);
                bool isFlagR = false;
                for (int i = 0; i < R_Axises.Count(); i++)//判断R轴是否需要调整位置
                {
                    if (!R_Axises[i].CheckIsInPosition(Status.RAxisPositions[i]))
                    {
                        isFlagR = true;
                        break;
                    }
                }
                if (isFlagR)//是否有R轴需要旋转的，需要旋转的先张开变距轴
                {
                    if (!IsFoolProofingZ_Axise())//Z轴没有在飞拍以上点位，就需要Z轴升上来
                    {
                        for (int i = 0; i < Z_Axises.Count(); i++)
                        {
                            await Z_Axises[i].MoveToAsync(Z待机位);
                        }
                        await Task.Delay(100, CancellationToken);
                    }
                    if (JiaZhuaBianJu_Axis.CheckIsInPosition(BJ_张开位))//变距轴在张开位，就执行旋转R轴
                    {
                        for (int i = 0; i < R_Axises.Count(); i++)
                        {
                            var axisPositions_R = Status.RAxisPositions[i];
                            if (!R_Axises[i].CheckIsInPosition(Status.RAxisPositions[i]))
                            {
                                await R_Axises[i].MoveToAsync(axisPositions_R);
                            }
                        }
                        await Task.Delay(100, CancellationToken);
                    }
                    else //变距轴不在张开位，执行变距轴张开，R轴再旋转，然后再回锁紧位
                    {
                        await JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, CancellationToken);
                        await CheckCancellationToken();
                        await Task.Delay(100, CancellationToken);
                        for (int i = 0; i < R_Axises.Count(); i++)
                        {
                            var axisPositions_R = Status.RAxisPositions[i];
                            if (!R_Axises[i].CheckIsInPosition(Status.RAxisPositions[i]))
                            {
                                await R_Axises[i].MoveToAsync(axisPositions_R);
                            }
                        }
                        await Task.Delay(100, CancellationToken);
                        await JiaZhuaBianJu_Axis.MoveToAsync(BJ_缩紧位, CancellationToken);
                    }
                    isFlagR = true;
                }
                if (!X_Axis.CheckIsInPosition(Status.XAxisPositions) || !Y_Axis.CheckIsInPosition(Status.YAxisPositions))
                {
                    if (!IsFoolProofingZ_Axise())//Z轴没有在飞拍以上点位，就需要Z轴升上来
                    {
                        for (int i = 0; i < Z_Axises.Count(); i++)
                        {
                            await Z_Axises[i].MoveToAsync(Z待机位);
                        }
                        await Task.Delay(100, CancellationToken);
                    }
                    if (!X_Axis.CheckIsInPosition(Status.YAxisPositions))
                        await X_Axis.MoveToAsync(Status.XAxisPositions);
                    if (!Y_Axis.CheckIsInPosition(Status.YAxisPositions))
                        await Y_Axis.MoveToAsync(Status.YAxisPositions);
                    for (int i = 0; i < Z_Axises.Count(); i++)
                    {
                        var axisPositions_Z = Status.ZAxisPositions[i];
                        if (!Z_Axises[i].CheckIsInPosition(axisPositions_Z))
                        {
                            await Z_Axises[i].MoveToAsync(axisPositions_Z);
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < Z_Axises.Count(); i++)
                    {
                        var axisPositions_Z = Status.ZAxisPositions[i];
                        if (!Z_Axises[i].CheckIsInPosition(axisPositions_Z))
                        {
                            await Z_Axises[i].MoveToAsync(axisPositions_Z);
                        }
                    }
                }
                LogInfo($"运行状态恢复->[结束]");
            }
            catch (Exception ex)
            {
                _isRecoverPreRunningError = true;
                Root.Stop();
                LogError($"运行状态恢复->[异常]{ex.Message}", ex);
            }
        }
        void ThrowException(string message)
        {
            throw new InvalidOperationException(message);
        }
        #endregion

        #region 公共方法
        IOptionRepository _optionRepository;
        public override async Task InitializeAsync()
        {
            _optionRepository = Service.GetRequiredService<IOptionRepository>();
            _inspectorOption = _optionRepository.Get<InspectorOption>();
            Status = RunningStatus.GetRecord<BanYunRunningStatus>("BanYun.json");
            Logger = Service.GetService<ILoggerFactory>().CreateLogger("BanYunStation");
            await FoxconnMES.InitializeAsync();
            await base.InitializeAsync();
        }
        public void ClearAlarm()
        {
            XYUnloadNGError = false;
            FlaySnapNGWraning = false;
            NGTrayFullError = false;
            NGTrayNoReadyError = false;
            LiJuError = false;
        }
        public void OnStepChanged(string step)
        {
            StepsChanged?.SafeInvoke(this, step);
        }
        public void OnNozzelProductChanged()
        {
            NozzelsProductChanged?.SafeInvoke(this, Status.NozzleStatus);
        }
        public void SetFlyCapture()
        {
            double[] positions = [
                Y_Axis.GetTargetPosition(Y夹爪1飞拍位),
                Y_Axis.GetTargetPosition(Y夹爪2飞拍位),
                Y_Axis.GetTargetPosition(Y夹爪3飞拍位),
                Y_Axis.GetTargetPosition(Y夹爪4飞拍位),
                Y_Axis.GetTargetPosition(Y夹爪5飞拍位),
                Y_Axis.GetTargetPosition(Y夹爪6飞拍位),
                Y_Axis.GetTargetPosition(Y夹爪7飞拍位),
            ];
            int length = positions.Length;
            double rate = Y_Axis.Equivalent;
            double current = Y_Axis.Current;
            Electronic.Controller.SetExtraEncoder(0);
            double[] capturePoint = new double[length];
            for (int i = 0; i < length; i++)
            {
                capturePoint[i] = (positions[i] - current) * rate;
            }
            if (current > positions[6])
            {
                double[] temp = new double[length];
                Array.Copy(capturePoint, temp, length);
                for (int i = 0; i < length; i++)
                {
                    capturePoint[i] = temp[6 - i];
                }
            }
            Electronic.Controller.SetupTriggerTable(5, capturePoint);
        }
        public void SetFlyCapture2(List<double> positions)
        {
            int length = positions.Count;
            double rate = Y_Axis.Equivalent;
            Electronic.Controller.SetExtraEncoder(0);
            double[] capturePoint = new double[length];
            for (int i = 0; i < length; i++)
            {
                capturePoint[i] = (positions[i]) * rate;
            }
            Electronic.Controller.SetupTriggerTable(4, capturePoint);
        }
        public void ClearFlyCapture()
        {
            Electronic.Controller.ClearTriggerTable(4);
            Electronic.Controller.ClearTriggerTable(5);
        }
        public async Task BottomCameraRotationCenterCalibration(bool isUseSiMo1, CancellationToken cancellationToken, bool isAutoSave, bool isRotationCenterCalibration)
        {
            if (!_isInitialized) return;
            OnStepChanged("旋转中心标定飞拍1");
            string p = isUseSiMo1 ? X飞拍位1 : X飞拍位2;
            LogInfo("移动XY到飞拍位置,夹爪变距张开");
            await Task.WhenAll(X_Axis.MoveToAsync(p, cancellationToken), Y_Axis.MoveToAsync(Y飞拍起始位, cancellationToken), Camera_Axis.MoveToAsync(p, cancellationToken), JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, cancellationToken));
            LogInfo("XY已移动到飞拍位置，R轴旋转到撕膜位");
            string position = isUseSiMo1 ? XYR撕膜位1 : XYR撕膜位2;
            await Parallel.ForEachAsync(R_Axises, cancellationToken, async (x, t) => await x.MoveToAsync(position, cancellationToken));
            LogInfo("R轴已旋转到撕膜位，Z轴到飞拍位");
            await Parallel.ForEachAsync(Z_Axises, cancellationToken, async (x, t) => await x.MoveToAsync(Z飞拍位, cancellationToken));
            LogInfo("Z轴已到飞拍位，Y轴移动飞拍");
            string barcode = $"Calib_{DateTime.Now:HHmmss}";
            await Vision.StartAsync(barcode);
            CaptureFlag captureFlag = isUseSiMo1 ? CaptureFlag.Calib_0 : CaptureFlag.Calib_1;
            await Vision.PrepearBottomFlyCapture(captureFlag, isUseSiMo1, CurrentFeedTrayCol, barcode);
            SetFlyCapture();
            await Y_Axis.MoveToAsync(position, cancellationToken);
            LogInfo("飞拍1结束");

            var b = await Vision.BottomRotationCenterCalibration(isUseSiMo1, captureFlag, 1, isAutoSave, isRotationCenterCalibration);
            if (!b)
            {
                LogError("标定飞拍1失败"); return;
            }
            await Task.Delay(200);
            LogInfo("Y轴移动到飞拍起始位");
            await Y_Axis.MoveToAsync(Y飞拍起始位, cancellationToken);

            LogInfo("R轴旋转180°");
            double angle = 180;
            var r1 = R1_Axis.GetTargetPosition(position) + angle;
            var r2 = R2_Axis.GetTargetPosition(position) + angle;
            var r3 = R3_Axis.GetTargetPosition(position) + angle;
            var r4 = R4_Axis.GetTargetPosition(position) + angle;
            var r5 = R5_Axis.GetTargetPosition(position) + angle;
            var r6 = R6_Axis.GetTargetPosition(position) + angle;
            var r7 = R7_Axis.GetTargetPosition(position) + angle;
            var speed1 = R1_Axis.GetVelocityCurve(position);
            var speed2 = R2_Axis.GetVelocityCurve(position);
            var speed3 = R3_Axis.GetVelocityCurve(position);
            var speed4 = R4_Axis.GetVelocityCurve(position);
            var speed5 = R5_Axis.GetVelocityCurve(position);
            var speed6 = R6_Axis.GetVelocityCurve(position);
            var speed7 = R7_Axis.GetVelocityCurve(position);

            await Parallel.ForEachAsync([(R1_Axis, r1, speed1), (R2_Axis, r2, speed2), (R3_Axis, r3, speed3), (R4_Axis, r4, speed4), (R5_Axis, r5, speed5), (R6_Axis, r6, speed6), (R7_Axis, r7, speed7)], cancellationToken, async (x, t) => await x.Item1.MoveToAsync(x.Item2, x.Item3, t));
            LogInfo("R轴旋转180°完成");

            await Task.Delay(200);
            LogInfo("Y轴已到起始位，开始飞拍2");
            CaptureFlag captureFlag2 = isUseSiMo1 ? CaptureFlag.Calib_1 : CaptureFlag.Calib_0;
            await Vision.PrepearBottomFlyCapture(captureFlag2, isUseSiMo1, 2, barcode);
            SetFlyCapture();
            await Y_Axis.MoveToAsync(position, cancellationToken);
            LogInfo("飞拍2结束,R轴旋转到撕膜位");
            await Parallel.ForEachAsync(R_Axises, cancellationToken, async (x, t) => await x.MoveToAsync(position, cancellationToken));
            if (!await Vision.BottomRotationCenterCalibration(isUseSiMo1, captureFlag2, 2, isAutoSave, isRotationCenterCalibration))
            {
                LogError("标定飞拍2失败"); return;
            }
        }

        /// <summary>
        /// 移动XY轴到指定坐标
        /// </summary>
        /// <param name="destX"></param>
        /// <param name="destY"></param>
        /// <returns></returns>
        public async Task MoveXYAxis(double destX, double destY, CancellationToken cancellationToken)
        {
            if (!_isInitialized)
                throw new Exception("移动XY轴前请完成设备初始化!");
            if (!IsFoolProofingZ_Axise())
                throw new Exception("移动XY轴时Z轴不在安全位置!");
            await Parallel.ForEachAsync([(X_Axis, destX), (Y_Axis, destY)], cancellationToken, async (x, t) => { await x.Item1.MoveToAsync(x.Item2, null, t); });
        }
        #endregion

        #region 私有方法
        private void SaveRuningRecordState()
        {
            if (_isInitialized)
            {
                Status.XAxisPositions = X_Axis.Current;
                Status.YAxisPositions = Y_Axis.Current;
                Status.BJAxisPositions = JiaZhuaBianJu_Axis.Current;
                Status.ZAxisPositions = Z_Axises.Select(x => x.Current).ToArray();
                Status.RAxisPositions = R_Axises.Select(x => x.Current).ToArray();
                Status.CameraAxisPositions = Camera_Axis.Current;
            }
            #region 如果发生异常把之前状态赋值回去
            if (_isRecoverPreRunningError && _preRunStatus != null)
            {
                Status = _preRunStatus;
            }
            #endregion
            Status.Save();
        }
        private void SaveRuningRecordStateInit()
        {
            Status.XAxisPositions = X_Axis.Current;
            Status.YAxisPositions = Y_Axis.Current;
            Status.BJAxisPositions = JiaZhuaBianJu_Axis.Current;
            Status.ZAxisPositions = Z_Axises.Select(x => x.Current).ToArray();
            Status.Save();
        }

        protected IEnumerable<DmcAxis> GetAxes()
        {
            return Automatics.Where(x => x is DmcAxis).Cast<DmcAxis>().ToArray();
        }
        /// <summary>
        /// 对于7根夹爪上Z轴ID
        /// </summary>
        ushort[] nodeNums = new ushort[] { 1010, 1012, 1014, 1016, 1018, 1020, 1022 };//1-7对应Z轴
        /// <summary>
        /// 计算力矩
        /// </summary>
        /// <returns></returns>
        private async Task CalcLiJu(string stepName)
        {
            await Task.Run(async () =>
            {
                LogInfo($"{stepName}->[测试力矩开始]");
                var lijuModels = new List<LijuModel>();
                var dataStorageService = Service.GetService<IDataStorageService>();
                var liJuDictionariey = new ConcurrentDictionary<int, double>();
                await Task.Delay(500);
                lijuModels.Clear();
                for (int i = 0; i < nodeNums.Count(); i++)
                {
                    var nodeNum = nodeNums[i];
                    short outValue = 0;
                    //uint outValuBase = 0;//额定电流
                    //Electronic.Controller.GetNodeOd(0, 2, nodeNum, 0x6075, 0, 32, ref outValuBase);
                    Electronic.Controller.GetNodeOd(0, 2, nodeNum, 0x6077, 0, 16, ref outValue);
                    var lijuModel = new LijuModel() { Number = i + 1, Current = outValue, Base = 1.6 };
                    //lijuModel.Calc(_inspectorOption.LijuTolerance.IsUse, _inspectorOption.LijuTolerance.UpperLimit);
                    lijuModel.Calc2(_inspectorOption.LijuTolerance.IsUse, _inspectorOption.LijuTolerance.UpperLimit);
                    lijuModels.Add(lijuModel);
                    liJuDictionariey[lijuModel.Number] = lijuModel.Offset;
                }
                dataStorageService.LiJuDictionaries = liJuDictionariey;
                LiJuChanged?.Invoke(this, lijuModels);
                if (lijuModels.Any(x => x.Quality == Quality.Ng))
                {
                    LiJuError = true;
                    LogInfo($"{stepName}->[测试力矩异常[{string.Join("|", lijuModels.Select(x => x.Offset))}][{string.Join("|", lijuModels.Select(x => x.Quality))}]");
                }
                else
                {
                    LogInfo($"{stepName}->[测试力矩结束[{string.Join("|", lijuModels.Select(x => x.Offset))}][{string.Join("|", lijuModels.Select(x => x.Quality))}]");
                }
            });
        }

        public List<double> CalcLiJuAvg()
        {
            var lijuModels = new List<LijuModel>();
            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < nodeNums.Count(); j++)
                {
                    var nodeNum = nodeNums[j];
                    short outValue = 0;
                    uint outValuBase = 0;//额定电流
                    Electronic.Controller.GetNodeOd(0, 2, nodeNum, 0x6075, 0, 32, ref outValuBase);
                    Electronic.Controller.GetNodeOd(0, 2, nodeNum, 0x6077, 0, 16, ref outValue);
                    var lijuModel = new LijuModel() { Number = j + 1, Current = outValue, Base = outValuBase / 1000 };
                    lijuModel.Calc2(_inspectorOption.LijuTolerance.IsUse, _inspectorOption.LijuTolerance.UpperLimit);
                    lijuModels.Add(lijuModel);
                }
            }
            List<double> avglist = new List<double>();
            for (int i = 1; i <= 7; i++)
            {
                var lijuList = lijuModels.Where(x => x.Number == i);
                var avg = lijuList.Sum(x => x.Offset) / lijuList.Count();
                avglist.Add(avg);
            }
            return avglist;
        }
        /// <summary>
        /// 获取吸嘴上有产品的状态
        /// </summary>
        /// <returns></returns>
        private List<int> GetNozzleProductStateNumbers(bool isIsReverse = false)
        {
            List<int> numbers = new List<int>();
            if (isIsReverse)//吸嘴7-1
            {
                for (int i = 0; i < Status.NozzleStatus.Count(); i++)
                {
                    var state = Status.NozzleStatus[i];
                    if (state != TrayPointStatus.Empty && state != TrayPointStatus.NG)
                    {
                        int number = i + 1;
                        number = Math.Abs(number - 8);
                        numbers.Add(number);
                    }
                }
            }
            else //吸嘴1-7
            {
                for (int i = 0; i < Status.NozzleStatus.Count(); i++)
                {
                    var state = Status.NozzleStatus[i];
                    if (state != TrayPointStatus.Empty && state != TrayPointStatus.NG)
                    {
                        numbers.Add(i + 1);
                    }
                }
            }
            return numbers;
        }
        /// <summary>
        /// 获取当前产品角度,旋转R轴,单排0°,双排180°
        /// </summary>
        /// <returns></returns>
        private bool ProductDirection(int col)
        {
            return ((col + 1) % 2) == 0;
        }

        /// <summary>
        /// 获取入料盘取料时X坐标偏移,和当前列产品状态
        /// </summary>
        /// <returns></returns>
        private double GetFeedTrayOffset(int col)
        {
            var px = -((col - 1) / 2) * FeedTray.Instance.ColDistance;
            return px;
        }

        /// <summary>
        /// 获取入料盘取料时Y坐标偏移
        /// </summary>
        /// <returns></returns>
        private double GetFeedTrayOffsetY(int row)
        {
            var py = row * FeedTray.Instance.RowDistance;
            return py;
        }
        private async Task MoveXYToOriginal(string stepName)
        {
            LogInfo($"{stepName}->Z轴移动到待机位");
            await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => { await x.MoveToAsync(Z待机位, t); });
            LogInfo($"{stepName}->XY轴移动到待机位");
            await Task.WhenAll
            (
                X_Axis.MoveToAsync(X待机位, CancellationToken).ContinueWith(x => LogInfo($"{stepName}->{X_Axis.Name}已移动到待机位")),
                Y_Axis.MoveToAsync(Y待机位, CancellationToken).ContinueWith(x => LogInfo($"{stepName}->{Y_Axis.Name}已移动到待机位")),
                JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, CancellationToken).ContinueWith(x => LogInfo($"{stepName}->{JiaZhuaBianJu_Axis.Name}变距已移动到张开位"))
            );
            await CheckCancellationToken();//如果轮询取消刚好被轮询错过，就不会出现异常,所以增加1ms来判断令牌是否被取消
        }
        /// <summary>
        /// 检查是否有产品
        /// </summary>
        /// <returns></returns>
        private bool IsCheckProductState()
        {
            var colStatus = FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1];
            if (colStatus.Items.All(x => x.Status == TrayPointStatus.Empty || x.Status == TrayPointStatus.CompletedOK))
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 检查是否吸真空异常
        /// </summary>
        /// <returns></returns>
        private async Task<bool> CheckVacuoError(string stepName)
        {
            if (_inspectorOption.IsDryRunMode)
            {
                return false;
            }
            var nozzles = Functions.SelectObjects(Nozzles, Status.NozzleStatus.Select(x => x == TrayPointStatus.OK).ToList());
            var tasks = new List<Task<bool>>();
            foreach (var item in nozzles)
            {
                tasks.Add(item.SuckAndCheckAsync());
            }
            var result = await Task.WhenAll(tasks);
            if (!result.All(x => x))
            {
                LogError($"{stepName}->[吸嘴取产品真空报警]");
                await Task.Delay(500);
                return true;
            }
            return false;
        }
        /// <summary>
        /// 获取取料列数
        /// </summary>
        /// <param name="currentCol"></param>
        /// <param name="reverse">是否切换方向：奇数列切换到偶数列</param>
        /// <param name="isNewTray">是否换新Tray</param>
        /// <returns></returns>
        private int GetNextColumn(int currentFeedTrayCol, out bool reverse, out bool isNewTray)
        {
            reverse = false;
            isNewTray = false;
            var newCol = currentFeedTrayCol + 2;
            if (newCol > FeedTray.Instance.Col)
            {
                if (newCol % 2 == 1)
                {
                    reverse = true;
                    newCol = 2;
                }
                else
                {
                    isNewTray = true;
                    newCol = 1;
                }
            }
            return newCol;
        }

        /// <summary>
        /// 检查令牌是否被取消
        /// </summary>
        /// <returns></returns>
        private async Task CheckCancellationToken()
        {
            await Task.Delay(1, CancellationToken);
        }
        #endregion

        #region 防呆方法
        /// <summary>
        /// 防呆Z轴没有在飞拍安全位 True表示安全，False表示危险
        /// </summary>
        /// <returns></returns>
        private bool IsFoolProofingZ_Axise()
        {
            return Z_Axises.All(x => x.Current <= x.GetTargetPosition(Z飞拍位) + 0.1);
        }
        #endregion
    }
    public enum BanYunStationRunStep
    {
        Step01_等待入料盘就绪,
        Step02_上相机飞拍_读码,
        Step03_XYR移动取料位,
        Step04_从料盘取料,
        Step05_等待撕膜就绪,
        Step06_下相机飞拍_对位,
        Step07_移动撕膜位,
        Step08_等待撕膜完成,
        Step09_下相机飞拍_复检,
        Step10_放OK料,
        Step11_放NG料,
        Step12_MES进站,
        Step13_MES出站,
        Step14_MESLQ,
    }
    #region TODO 旧
    //namespace VIA.SiMoJi.Domain.Inspection
    //{
    //    public class BanYunStation : StationBase<BanYunStationOption>, ISuportClearAlarm
    //    {
    //        #region 字段
    //        public static bool IsUseSiMo1 => SignalPanel.Signal.IsUseSiMo1;
    //        public volatile VisionStation Vision;
    //        public volatile GongLiaoStation GongLiaoStation;
    //        public volatile SiMoStation SiMoStation;
    //        private InspectorOption _inspectorOption;
    //        public BanYunRunningStatus Status;
    //        private bool isAxisSaveAlarm;
    //        private bool feedTrayError;
    //        private bool flaySnapError;
    //        private bool ngTrayError;
    //        private ICurrentRecipe _currentRecipe;
    //        private bool ngNoReadyError;
    //        bool _isInit;
    //        private bool nozzelVaccumError;
    //        Dictionary<int, string> _stepDesc = new()
    //        {
    //                { 0, "等待入料盘到位信号" },
    //                { 1, "XY到取料位" },
    //                { 2, "吸嘴取料" },
    //                { 3, "等待撕膜就绪信号" },
    //                { 4, "一次飞拍" },
    //                { 5, "移动XYZ到撕膜位" },
    //                { 6, "等待撕膜完成信号" },
    //                { 7, "二次飞拍" },
    //                { 8, "OK放料" },
    //                { 9, "NG放料" },
    //         };
    //        #endregion

    //        #region 位置

    //        private const string X待机位 = "待机位";
    //        private const string X飞拍位1 = "飞拍位1";
    //        private const string X飞拍位2 = "飞拍位2";
    //        private const string XYR撕膜位1 = "撕膜位1";
    //        private const string XYR撕膜位2 = "撕膜位2";

    //        private const string 上相机读码位1 = "上相机读码位1";
    //        private const string 上相机读码位2 = "上相机读码位2";

    //        private const string C飞拍位1 = "飞拍位1";
    //        private const string C飞拍位2 = "飞拍位2";

    //        private const string Y待机位 = "待机位";
    //        private const string Y飞拍起始位 = "飞拍起始位";
    //        private const string Y夹爪1飞拍位 = "夹爪1飞拍位";
    //        private const string Y夹爪2飞拍位 = "夹爪2飞拍位";
    //        private const string Y夹爪3飞拍位 = "夹爪3飞拍位";
    //        private const string Y夹爪4飞拍位 = "夹爪4飞拍位";
    //        private const string Y夹爪5飞拍位 = "夹爪5飞拍位";
    //        private const string Y夹爪6飞拍位 = "夹爪6飞拍位";
    //        private const string Y夹爪7飞拍位 = "夹爪7飞拍位";
    //        private const string XY_NG下料位 = "NG下料位";
    //        private const string XY_压力测试位 = "压力测试位";
    //        private const string XY_NG下料避让位 = "NG放料避让位";
    //        private const string XYR取料位1 = "取料位1";
    //        private const string XYR取料位2 = "取料位2";

    //        private const string 待机位 = "待机位";
    //        private const string Z待机位 = "待机位";
    //        private const string Z取料位 = "取料位";
    //        private const string Z飞拍位 = "飞拍位";
    //        private const string Z放料位 = "放料位";
    //        private const string Z撕膜位1 = "撕膜位1";
    //        private const string Z撕膜位2 = "撕膜位2";
    //        public const string Z_NG放料位 = "NG放料位";
    //        public const string Z_压力测试起始位 = "压力测试起始位";
    //        public const string Z_压力测试终止位 = "压力测试终止位";
    //        private const string R_NG放料位 = "NG放料位";
    //        private const string R待机位 = "待机位";

    //        private const string BJ_张开位 = "张开位";
    //        private const string BJ_缩紧位 = "缩紧位";

    //        private const string 备用 = "备用";

    //        #endregion

    //        #region 硬件

    //        [MotionPath(BJ_张开位)]
    //        [MotionPath(BJ_缩紧位)]
    //        public IServoAxis JiaZhuaBianJu_Axis { get; }

    //        [MotionPath(X待机位)]
    //        [MotionPath(XYR取料位1)]
    //        [MotionPath(XYR取料位2)]
    //        [MotionPath(X飞拍位1)]
    //        [MotionPath(X飞拍位2)]
    //        [MotionPath(XYR撕膜位1)]
    //        [MotionPath(XYR撕膜位2)]
    //        [MotionPath(XY_NG下料位)]
    //        [MotionPath(XY_NG下料避让位)]
    //        [MotionPath(XY_压力测试位)]
    //        [MotionPath(上相机读码位1)]
    //        [MotionPath(上相机读码位2)]
    //        [MotionPath(备用)]
    //        public IServoAxis X_Axis { get; }

    //        [MotionPath(Y待机位)]
    //        [MotionPath(XYR取料位1)]
    //        [MotionPath(XYR取料位2)]
    //        [MotionPath(XYR撕膜位1)]
    //        [MotionPath(XYR撕膜位2)]
    //        [MotionPath(Y飞拍起始位)]
    //        [MotionPath(Y夹爪1飞拍位)]
    //        [MotionPath(Y夹爪2飞拍位)]
    //        [MotionPath(Y夹爪3飞拍位)]
    //        [MotionPath(Y夹爪4飞拍位)]
    //        [MotionPath(Y夹爪5飞拍位)]
    //        [MotionPath(Y夹爪6飞拍位)]
    //        [MotionPath(Y夹爪7飞拍位)]
    //        [MotionPath(XY_NG下料位)]
    //        [MotionPath(XY_NG下料避让位)]
    //        [MotionPath(XY_压力测试位)]
    //        [MotionPath(上相机读码位1)]
    //        [MotionPath(上相机读码位2)]
    //        [MotionPath(备用)]
    //        public IServoAxis Y_Axis { get; }
    //        [MotionPath(C飞拍位1)]
    //        [MotionPath(C飞拍位2)]
    //        [MotionPath(备用)]
    //        public IServoAxis Camera_Axis { get; }
    //        [MotionPath(R待机位)]
    //        [MotionPath(XYR取料位1)]
    //        [MotionPath(XYR取料位2)]
    //        [MotionPath(XYR撕膜位1)]
    //        [MotionPath(XYR撕膜位2)]
    //        [MotionPath(R_NG放料位)]
    //        public IServoAxis R1_Axis { get; }
    //        [MotionPath(R待机位)]
    //        [MotionPath(XYR取料位1)]
    //        [MotionPath(XYR取料位2)]
    //        [MotionPath(XYR撕膜位1)]
    //        [MotionPath(XYR撕膜位2)]
    //        [MotionPath(R_NG放料位)]
    //        public IServoAxis R2_Axis { get; }
    //        [MotionPath(R待机位)]
    //        [MotionPath(XYR取料位1)]
    //        [MotionPath(XYR取料位2)]
    //        [MotionPath(XYR撕膜位1)]
    //        [MotionPath(XYR撕膜位2)]
    //        [MotionPath(R_NG放料位)]
    //        public IServoAxis R3_Axis { get; }
    //        [MotionPath(R待机位)]
    //        [MotionPath(XYR取料位1)]
    //        [MotionPath(XYR取料位2)]
    //        [MotionPath(XYR撕膜位1)]
    //        [MotionPath(XYR撕膜位2)]
    //        [MotionPath(R_NG放料位)]
    //        public IServoAxis R4_Axis { get; }
    //        [MotionPath(R待机位)]
    //        [MotionPath(XYR取料位1)]
    //        [MotionPath(XYR取料位2)]
    //        [MotionPath(XYR撕膜位1)]
    //        [MotionPath(XYR撕膜位2)]
    //        [MotionPath(R_NG放料位)]
    //        public IServoAxis R5_Axis { get; }
    //        [MotionPath(R待机位)]
    //        [MotionPath(XYR取料位1)]
    //        [MotionPath(XYR取料位2)]
    //        [MotionPath(XYR撕膜位1)]
    //        [MotionPath(XYR撕膜位2)]
    //        [MotionPath(R_NG放料位)]
    //        public IServoAxis R6_Axis { get; }
    //        [MotionPath(R待机位)]
    //        [MotionPath(XYR取料位1)]
    //        [MotionPath(XYR取料位2)]
    //        [MotionPath(XYR撕膜位1)]
    //        [MotionPath(XYR撕膜位2)]
    //        [MotionPath(R_NG放料位)]
    //        public IServoAxis R7_Axis { get; }
    //        [MotionPath(Z待机位)]
    //        [MotionPath(Z取料位)]
    //        [MotionPath(Z飞拍位)]
    //        [MotionPath(Z撕膜位1)]
    //        [MotionPath(Z撕膜位2)]
    //        [MotionPath(Z放料位)]
    //        [MotionPath(Z_NG放料位)]
    //        [MotionPath(Z_压力测试起始位)]
    //        [MotionPath(Z_压力测试终止位)]
    //        public IServoAxis Z1_Axis { get; }
    //        [MotionPath(Z待机位)]
    //        [MotionPath(Z取料位)]
    //        [MotionPath(Z飞拍位)]
    //        [MotionPath(Z撕膜位1)]
    //        [MotionPath(Z撕膜位2)]
    //        [MotionPath(Z放料位)]
    //        [MotionPath(Z_NG放料位)]
    //        [MotionPath(Z_压力测试起始位)]
    //        [MotionPath(Z_压力测试终止位)]
    //        public IServoAxis Z2_Axis { get; }
    //        [MotionPath(Z待机位)]
    //        [MotionPath(Z取料位)]
    //        [MotionPath(Z飞拍位)]
    //        [MotionPath(Z撕膜位1)]
    //        [MotionPath(Z撕膜位2)]
    //        [MotionPath(Z放料位)]
    //        [MotionPath(Z_NG放料位)]
    //        [MotionPath(Z_压力测试起始位)]
    //        [MotionPath(Z_压力测试终止位)]
    //        public IServoAxis Z3_Axis { get; }
    //        [MotionPath(Z待机位)]
    //        [MotionPath(Z取料位)]
    //        [MotionPath(Z飞拍位)]
    //        [MotionPath(Z撕膜位1)]
    //        [MotionPath(Z撕膜位2)]
    //        [MotionPath(Z放料位)]
    //        [MotionPath(Z_NG放料位)]
    //        [MotionPath(Z_压力测试起始位)]
    //        [MotionPath(Z_压力测试终止位)]
    //        public IServoAxis Z4_Axis { get; }
    //        [MotionPath(Z待机位)]
    //        [MotionPath(Z取料位)]
    //        [MotionPath(Z飞拍位)]
    //        [MotionPath(Z撕膜位1)]
    //        [MotionPath(Z撕膜位2)]
    //        [MotionPath(Z放料位)]
    //        [MotionPath(Z_NG放料位)]
    //        [MotionPath(Z_压力测试起始位)]
    //        [MotionPath(Z_压力测试终止位)]
    //        public IServoAxis Z5_Axis { get; }
    //        [MotionPath(Z待机位)]
    //        [MotionPath(Z取料位)]
    //        [MotionPath(Z飞拍位)]
    //        [MotionPath(Z撕膜位1)]
    //        [MotionPath(Z撕膜位2)]
    //        [MotionPath(Z放料位)]
    //        [MotionPath(Z_NG放料位)]
    //        [MotionPath(Z_压力测试起始位)]
    //        [MotionPath(Z_压力测试终止位)]
    //        public IServoAxis Z6_Axis { get; }
    //        [MotionPath(Z待机位)]
    //        [MotionPath(Z取料位)]
    //        [MotionPath(Z飞拍位)]
    //        [MotionPath(Z撕膜位1)]
    //        [MotionPath(Z撕膜位2)]
    //        [MotionPath(Z放料位)]
    //        [MotionPath(Z_NG放料位)]
    //        [MotionPath(Z_压力测试起始位)]
    //        [MotionPath(Z_压力测试终止位)]
    //        public IServoAxis Z7_Axis { get; }

    //        public List<IServoAxis> Z_Axises => [Z1_Axis, Z2_Axis, Z3_Axis, Z4_Axis, Z5_Axis, Z6_Axis, Z7_Axis];
    //        public List<IServoAxis> R_Axises => [R1_Axis, R2_Axis, R3_Axis, R4_Axis, R5_Axis, R6_Axis, R7_Axis];
    //        public List<Nozzle> Nozzles => [N_夹爪1吸嘴, N_夹爪2吸嘴, N_夹爪3吸嘴, N_夹爪4吸嘴, N_夹爪5吸嘴, N_夹爪6吸嘴, N_夹爪7吸嘴];

    //        public Nozzle N_夹爪1吸嘴 => Electronic.Default.Nozzle_夹爪1吸嘴;
    //        public Nozzle N_夹爪2吸嘴 => Electronic.Default.Nozzle_夹爪2吸嘴;
    //        public Nozzle N_夹爪3吸嘴 => Electronic.Default.Nozzle_夹爪3吸嘴;
    //        public Nozzle N_夹爪4吸嘴 => Electronic.Default.Nozzle_夹爪4吸嘴;
    //        public Nozzle N_夹爪5吸嘴 => Electronic.Default.Nozzle_夹爪5吸嘴;
    //        public Nozzle N_夹爪6吸嘴 => Electronic.Default.Nozzle_夹爪6吸嘴;
    //        public Nozzle N_夹爪7吸嘴 => Electronic.Default.Nozzle_夹爪7吸嘴;
    //        public CylinderEx C_无杆缸 => Electronic.Cylinder_NG下料无杆缸;
    //        public CylinderEx C_定位缸 => Electronic.Cylinder_NG下料抽屉定位气缸;
    //        public Feeder Feeder1 { get; set; }
    //        public Feeder Feeder2 { get; set; }

    //        #endregion

    //        #region 报警

    //        [Alarm(true, AlarmLevel.Error, "轴安全位报警", Logical.Equal)]
    //        public bool IsAxisSaveAlarm { get => isAxisSaveAlarm; set => NotifyAlarm(ref isAxisSaveAlarm, value); }
    //        [Alarm(true, AlarmLevel.Error, "供料盘拍照报警", Logical.Equal)]
    //        public bool FeedTrayError { get => feedTrayError; set => NotifyAlarm(ref feedTrayError, value); }
    //        [Alarm(true, AlarmLevel.Error, "飞拍视觉报警", Logical.Equal)]
    //        public bool FlaySnapError { get => flaySnapError; set => NotifyAlarm(ref flaySnapError, value); }
    //        [Alarm(true, AlarmLevel.Error, "NG料盘已满", Logical.Equal)]
    //        public bool NGTrayFullError
    //        {
    //            get => ngTrayError;
    //            set
    //            {
    //                NotifyAlarm(ref ngTrayError, value);
    //                if (value)
    //                {
    //                    NGTray.Instance.SetFull();
    //                }
    //            }
    //        }
    //        [Alarm(true, AlarmLevel.Error, "NG料盘未就绪", Logical.Equal)]
    //        public bool NGTrayNoReadyError
    //        {
    //            get => ngNoReadyError;
    //            set
    //            {
    //                NotifyAlarm(ref ngNoReadyError, value);
    //                if (value)
    //                {
    //                    NGTray.Instance.SetDisable();
    //                }
    //            }
    //        }
    //        [Alarm(true, AlarmLevel.Error, "取料真空报警", Logical.Equal)]
    //        public bool NozzelVaccumError { get => nozzelVaccumError; set => NotifyAlarm(ref nozzelVaccumError, value); }
    //        public int CurrentFeedTrayCol { get => Status.CurrentFeedTrayCol; set { Status.CurrentFeedTrayCol = value; CurrentFeedTrayColChanged.SafeInvoke(this, value); } }

    //        #endregion

    //        #region 属性

    //        public NGXiaLiao NGXiaoLiao { get; private set; }
    //        public Electronic Electronic => Electronic.Default;
    //        public int Step
    //        {
    //            get => Status.Step;
    //            set
    //            {
    //                Status.Step = value;
    //                Status?.Save();
    //            }
    //        }

    //        public event EventHandler<string> StepsChanged;
    //        public event EventHandler<int> CurrentFeedTrayColChanged;
    //        public event EventHandler<TrayPointStatus[]> NozzelsProductChanged;
    //        public event EventHandler<(bool isOK, int count)> ProductCompleted;
    //        /// <summary>
    //        /// 飞拍读码多次失败，弹窗事件
    //        /// </summary>
    //        public event Func<string, bool> FlyReadBarcoeNGChanged;
    //        public event EventHandler<IEnumerable<LijuModel>> LiJuChanged;

    //        #endregion

    //        public BanYunStation(NGXiaLiao nGXiaLiao)
    //        {
    //            RetryCount = 0;
    //            this.InitalizeAlarms();
    //            NGXiaoLiao = nGXiaLiao;
    //            LogGroup = LoggerCategory.RunningInfo;
    //            JiaZhuaBianJu_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(JiaZhuaBianJu_Axis), NoId = 5, Name = "夹爪变距伺服" };
    //            X_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(X_Axis), NoId = 6, Name = "搬运X轴", CanMove = IsZAxiesSave };
    //            Y_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Y_Axis), NoId = 7, Name = "搬运Y轴", CanMove = IsZAxiesSave };
    //            Camera_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Camera_Axis), NoId = 4, Name = "下相机轴" };
    //            Z1_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z1_Axis), NoId = 8, Name = "夹爪1_Z轴" };
    //            Z2_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z2_Axis), NoId = 10, Name = "夹爪2_Z轴" };
    //            Z3_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z3_Axis), NoId = 12, Name = "夹爪3_Z轴" };
    //            Z4_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z4_Axis), NoId = 14, Name = "夹爪4_Z轴" };
    //            Z5_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z5_Axis), NoId = 16, Name = "夹爪5_Z轴" };
    //            Z6_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z6_Axis), NoId = 18, Name = "夹爪6_Z轴" };
    //            Z7_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(Z7_Axis), NoId = 20, Name = "夹爪7_Z轴" };
    //            R1_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R1_Axis), NoId = 9, Name = "夹爪1_R轴" };
    //            R2_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R2_Axis), NoId = 11, Name = "夹爪2_R轴" };
    //            R3_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R3_Axis), NoId = 13, Name = "夹爪3_R轴" };
    //            R4_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R4_Axis), NoId = 15, Name = "夹爪4_R轴" };
    //            R5_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R5_Axis), NoId = 17, Name = "夹爪5_R轴" };
    //            R6_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R6_Axis), NoId = 19, Name = "夹爪6_R轴" };
    //            R7_Axis = new DmcAxis(Electronic.Controller) { Id = nameof(R7_Axis), NoId = 21, Name = "夹爪7_R轴" };
    //            Add(X_Axis, Y_Axis);
    //            Add(Camera_Axis, JiaZhuaBianJu_Axis);
    //            Add(Z1_Axis, Z2_Axis, Z3_Axis, Z4_Axis, Z5_Axis, Z6_Axis, Z7_Axis);
    //            Add(R1_Axis, R2_Axis, R3_Axis, R4_Axis, R5_Axis, R6_Axis, R7_Axis);
    //            Add(N_夹爪1吸嘴, N_夹爪2吸嘴, N_夹爪3吸嘴, N_夹爪4吸嘴, N_夹爪5吸嘴, N_夹爪6吸嘴, N_夹爪7吸嘴);
    //            Add(C_定位缸, C_无杆缸);

    //        }

    //        protected override async Task RunningCoreAsync()
    //        {
    //            await WaitFeedTrayReady(0);
    //            if (_inspectorOption.IsUseUpReadBarcode)//启用上相机读码 
    //            {
    //                var flyStepStateUp = FlyStepState.ChongShi;
    //                var flyReadCodeCountUp = 1;
    //                while (flyStepStateUp == FlyStepState.ChongShi || flyStepStateUp == FlyStepState.Rest)
    //                {
    //                    flyStepStateUp = await FeiPai3(10, flyReadCodeCountUp);
    //                    if (flyStepStateUp == FlyStepState.ChongShi)
    //                    {
    //                        flyReadCodeCountUp = flyReadCodeCountUp + 1;
    //                    }
    //                    if (flyStepStateUp == FlyStepState.Rest)
    //                    {
    //                        flyReadCodeCountUp = 0;
    //                    }
    //                }
    //            }
    //            await MoveXYToQuLiaoPosition(1);
    //            await QuLiao(2);
    //            await WaitSiMoReadySignal(3);
    //            var flyStepState = FlyStepState.ChongShi;
    //            var flyReadCodeCount = 1;
    //            while (flyStepState == FlyStepState.ChongShi || flyStepState == FlyStepState.Rest)
    //            {
    //                flyStepState = await FeiPai(4, flyReadCodeCount);
    //                if (flyStepState == FlyStepState.ChongShi)
    //                {
    //                    flyReadCodeCount = flyReadCodeCount + 1;
    //                }
    //                if (flyStepState == FlyStepState.Rest)
    //                {
    //                    flyReadCodeCount = 0;
    //                }
    //            }
    //            await MoveXYZToSiMoWei(5);
    //            await WaitSiMoCompleted(6);
    //            await FeiPai2(7);
    //            await OKFangLiao(8);
    //            await NGFangLiao(9);
    //        }

    //        public async Task<bool> InitializeStation(CancellationToken cancellationToken)
    //        {
    //            LogInfo("开始初始化...");
    //            OnStepChanged("初始化中");
    //            try
    //            {
    //                LogInfo("清空信号");
    //                SignalPanel.Signal.BanYunCompleted = false;
    //                var axies = this.Automatics.Where(x => x is DmcAxis).Cast<DmcAxis>().ToArray();
    //                axies.ForEach(x => x.Reset());
    //                axies.ForEach(x => x.ServoOn(true));
    //                await Task.Delay(500);
    //                LogInfo("Z轴回原点...");
    //                await Parallel.ForEachAsync(Z_Axises, cancellationToken, async (x, t) =>
    //                {
    //                    if (x.Current < 1)
    //                        await x.MoveDeltaAsync(1, null, t);
    //                    await x.MoveOriginAsync(t);
    //                    await x.MoveToAsync(Z待机位, t);
    //                });
    //                Status.ZAxisPositions = Z_Axises.Select(x => x.Current).ToArray();
    //                LogInfo("X/Y/变距轴/相机轴回原点开始...");
    //                await Parallel.ForEachAsync([Y_Axis, X_Axis, JiaZhuaBianJu_Axis, Camera_Axis], cancellationToken, async (x, t) => await x.MoveOriginAsync(t));

    //                LogInfo("变距轴开始到张开位置");
    //                await JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, cancellationToken);
    //                LogInfo("R轴回原点");
    //                await Parallel.ForEachAsync(R_Axises, cancellationToken, async (x, t) => await x.MoveOriginAsync(t));

    //                LogInfo("X/Y/R轴移动到待机位");
    //                await Parallel.ForEachAsync([.. R_Axises, X_Axis, Y_Axis], cancellationToken, async (x, t) => await x.MoveToAsync(待机位, t));

    //                var emptyNozzles = Status.NozzleStatus.Select(x => x == TrayPointStatus.Empty).ToList();
    //                var nozzels = Functions.SelectObjects(Nozzles, emptyNozzles);
    //                var task4 = new List<Task<bool>>();
    //                foreach (var item in nozzels)
    //                {
    //                    task4.Add(item.StopAndCheckAsync(cancellationToken, 3_000));
    //                }
    //                var bools4 = await Task.WhenAll(task4);
    //                if (bools4.Any(x => !x))
    //                {
    //                    LogError($"吸嘴破真空失败!");
    //                    return false;
    //                }
    //                if (Status.NozzleStatus.Any(x => x != TrayPointStatus.Empty))
    //                {
    //                    if (Step == 2)
    //                    {
    //                        Step = 1;
    //                    }
    //                    if (Step == 6)
    //                    {
    //                        Step = 5;
    //                    }
    //                }
    //                else
    //                {
    //                    Step = 0;
    //                    LogInfo("等待入料盘到位信号");
    //                }
    //                LogInfo("初始化完成");
    //                OnStepChanged(_stepDesc[Step]);
    //                CurrentFeedTrayColChanged.SafeInvoke(this, Status.CurrentFeedTrayCol);
    //                _isInit = true;
    //                return true;

    //            }
    //            catch (Exception ex)
    //            {
    //                LogError(ex.Message);
    //                return false;
    //            }
    //        }

    //        public async Task WaitFeedTrayReady(int step)
    //        {
    //            if (Step != step) return;
    //            LogInfo("等待入料盘到位信号");
    //            OnStepChanged("等待入料盘");
    //            await Judger.Sure(() => SignalPanel.Signal.FeedTrayReady, CancellationToken);
    //            Step = _inspectorOption.IsUseUpReadBarcode ? 10 : step + 1;
    //        }

    //        /// <summary>
    //        /// XY轴移动到取料位(取料),R轴旋转,下相机移动到飞拍位
    //        /// </summary>
    //        /// <param name="step"></param>
    //        /// <returns></returns>
    //        public async Task MoveXYToQuLiaoPosition(int step)
    //        {
    //            if (Step != step) return;
    //            OnStepChanged("XY到取料位");
    //            var currentFeedTrayColTemp = CurrentFeedTrayCol;
    //            if (!_inspectorOption.IsDryRunMode)
    //            {
    //                while (!IsCheckProductState())
    //                {
    //                    LogWarning($"当前料盘列{CurrentFeedTrayCol}无产品。");
    //                    CurrentFeedTrayCol = GetNextColumn(CurrentFeedTrayCol, out bool reverse, out bool isNewTray);
    //                    LogWarning($"寻找下一料盘列{CurrentFeedTrayCol}.");
    //                    if (isNewTray)
    //                    {
    //                        SignalPanel.Signal.FeedTrayCompleted = true;
    //                        LogInfo("入料盘取料完成,XYZ到待机位");
    //                        await Task.Delay(10);
    //                        await MoveXYToOriginal();
    //                        Step = 0;
    //                        return;
    //                    }
    //                }
    //            }
    //            var destName = ProductDirection(CurrentFeedTrayCol) ? XYR取料位1 : XYR取料位2;
    //            var offsetX = GetFeedTrayOffset(CurrentFeedTrayCol);
    //            var speedX = X_Axis.GetVelocityCurve(destName);
    //            var destX = X_Axis.GetTargetPosition(destName) + offsetX;
    //            var destY = Y_Axis.GetTargetPosition(destName);
    //            //var destX = X_Axis.GetTargetPosition(destName) + offsetX + SignalPanel.Signal.FeedTrayOffset.X;
    //            //var destY = Y_Axis.GetTargetPosition(destName) + SignalPanel.Signal.FeedTrayOffset.Y;
    //            var speedY = Y_Axis.GetVelocityCurve(destName);
    //            LogInfo("收入料盘到位信号,XY轴移动到取料位,夹爪变距张开,R轴旋转");
    //            var tasks = new List<Task>() {
    //                X_Axis.MoveToAsync(destX, speedX, CancellationToken).ContinueWith(x => LogInfo(X_Axis.Name + $"已移动到取料位{destX:F6}")),
    //                Y_Axis.MoveToAsync(destY, speedY,CancellationToken).ContinueWith(x => LogInfo(Y_Axis.Name + $"已移动到取料位")),
    //            };
    //            bool isRaxisNeedMove = R_Axises.Any(x => Math.Abs(x.Current - x.GetTargetPosition(destName)) > 0.1);
    //            if (isRaxisNeedMove)
    //            {
    //                tasks.Add(JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, CancellationToken).ContinueWith(x => LogInfo(JiaZhuaBianJu_Axis.Name + "变距已移动到张开位")));
    //            }
    //            await Task.WhenAll(tasks);
    //            if (isRaxisNeedMove)
    //            {
    //                LogInfo("开始将R轴移动到取料位");
    //                await Parallel.ForEachAsync(R_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(destName, t));
    //            }
    //            LogInfo("R轴已移动到取料位,开始将夹爪变距到缩紧位");
    //            await JiaZhuaBianJu_Axis.MoveToAsync(BJ_缩紧位, CancellationToken);
    //            Step = step + 1;
    //        }

    //        /// <summary>
    //        /// 取料:夹爪Z轴下降,吸真空,夹爪Z轴上升
    //        /// </summary>
    //        /// <param name="step"></param>
    //        /// <returns></returns>
    //        public async Task QuLiao(int step)
    //        {
    //            if (Step != step) return;
    //            OnStepChanged("吸嘴取料");
    //            LogInfo("获取吸嘴取料信息");
    //            var colStatus = FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1];
    //            if (_inspectorOption.IsDryRunMode)
    //            {
    //                Status.NozzleStatus = [TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK];
    //            }
    //            else
    //            {
    //                if (colStatus.Items.All(x => x.Status == TrayPointStatus.Empty))
    //                {
    //                    LogWarning($"当前料盘列{CurrentFeedTrayCol}无产品。");
    //                    CurrentFeedTrayCol = GetNextColumn(CurrentFeedTrayCol, out bool reverse, out bool isNewTray);
    //                    if (isNewTray)
    //                    {
    //                        if (!_inspectorOption.IsDryRunMode)
    //                        {
    //                            SignalPanel.Signal.FeedTrayCompleted = true;
    //                            LogInfo("入料盘取料完成,XYZ到待机位");
    //                            await Task.Delay(10);
    //                        }
    //                        await MoveXYToOriginal();
    //                        Step = 0;
    //                    }
    //                    return;
    //                }
    //                if (colStatus.RowCount != Status.NozzleStatus.Length)
    //                {
    //                    string error = $"料盘行数{colStatus.RowCount}和吸嘴数量{Status.NozzleStatus.Length}不一致";
    //                    LogError(error);
    //                    throw new Exception(error);
    //                }
    //                for (int i = 0; i < colStatus.RowCount; i++)
    //                {
    //                    Status.NozzleStatus = colStatus.Items.Select(x => x.Status).ToArray();
    //                }
    //            }
    //            LogInfo("夹爪已变距到缩紧位,Z轴下降到取料位");
    //            var z_axis = Functions.SelectObjects(Z_Axises, Status.NozzleStatus.Select(x => x == TrayPointStatus.OK || x == TrayPointStatus.NG).ToList());
    //            if (!_inspectorOption.IsDryRunMode)//不等于空跑模式,先提前吸真空
    //            {
    //                var nozzles = Functions.SelectObjects(Nozzles, Status.NozzleStatus.Select(x => x == TrayPointStatus.OK || x == TrayPointStatus.NG).ToList());
    //                for (int i = 0; i < nozzles.Count(); i++)
    //                {
    //                    nozzles[i].SuckAsync();
    //                }
    //            }
    //            await Parallel.ForEachAsync(z_axis, CancellationToken, async (x, t) => await x.MoveToAsync(Z取料位, t));
    //            if (_inspectorOption.IsDryRunMode)// 空跑模式
    //            {
    //                foreach (var item in Nozzles)
    //                {
    //                    item.SuckAsync();
    //                }
    //                await Task.Delay(200);
    //                foreach (var item in Nozzles)
    //                {
    //                    item.BrokenAsync();
    //                    await Task.Delay(100);
    //                    item.StopAsync();
    //                }
    //            }
    //            else  // 正常模式
    //            {
    //                var nozzles = Functions.SelectObjects(Nozzles, Status.NozzleStatus.Select(x => x == TrayPointStatus.OK || x == TrayPointStatus.NG).ToList());
    //                await Task.Delay(_inspectorOption.VaccumOnDelay);
    //                for (int i = 0; i < nozzles.Count(); i++)
    //                {
    //                    if (!nozzles[i].IsOn())
    //                    {
    //                        nozzles[i].IsSensorOnError = true;
    //                    }
    //                }
    //                if (nozzles.All(x => x.IsSensorOnError))
    //                {
    //                    LogError("吸嘴取产品真空报警。");
    //                    await Task.Delay(500);
    //                    return;
    //                }
    //            }
    //            LogInfo("Z轴开始上升到飞拍位");
    //            await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z飞拍位, t));
    //            OnNozzelProductChanged();
    //            Step = step + 1;
    //        }
    //        //检查是否有产品
    //        bool IsCheckProductState()
    //        {
    //            var colStatus = FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1];
    //            if (colStatus.Items.All(x => x.Status == TrayPointStatus.Empty))
    //            {
    //                return false;
    //            }
    //            return true;
    //        }

    //        /// <summary>
    //        /// 等待撕膜工位就绪信号
    //        /// </summary>
    //        /// <param name="step"></param>
    //        /// <returns></returns>
    //        public async Task WaitSiMoReadySignal(int step)
    //        {
    //            if (Step != step) return;
    //            OnStepChanged("等待撕膜信号");
    //            LogInfo("等待撕膜工位就绪信号");
    //            if (await CheckVacuoError()) return;
    //            await Judger.Sure(() => SignalPanel.Signal.SiMoReady, CancellationToken);
    //            Step = step + 1; ;
    //        }

    //        /// <summary>
    //        /// Y轴移动飞拍,并且直接移动到撕膜位置
    //        /// </summary>
    //        /// <param name="step"></param>
    //        /// <returns></returns>
    //        public async Task<FlyStepState> FeiPai(int step, int currentFlyReadCodeCount)
    //        {
    //            if (Step != step) return FlyStepState.TiaoGuo;
    //            OnStepChanged("一次飞拍");
    //            string p = IsUseSiMo1 ? X飞拍位1 : X飞拍位2;
    //            LogInfo("收到撕膜工位就绪信号,开始移动XY到飞拍位置,夹爪变距张开");
    //            await Task.WhenAll(X_Axis.MoveToAsync(p, CancellationToken), Y_Axis.MoveToAsync(Y飞拍起始位, CancellationToken), Camera_Axis.MoveToAsync(p, CancellationToken), JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, CancellationToken));
    //            LogInfo("XY已移动到飞拍位置，R轴旋转到撕膜位");
    //            string position = IsUseSiMo1 ? XYR撕膜位1 : XYR撕膜位2;
    //            CaptureFlag captureFlag = IsUseSiMo1 ? CaptureFlag.DuiWei_0 : CaptureFlag.DuiWei_1;
    //            await Parallel.ForEachAsync(R_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(position, CancellationToken));
    //            LogInfo("R轴已旋转到撕膜位，Y轴移动飞拍");
    //            //await Vision.PrepearBottomFlyCapture(captureFlag, IsUseSiMo1, CurrentFeedTrayCol, SignalPanel.Signal.CurrentFeedTray);
    //            var flyCaptureLists = GetNozzleProductStateNumbers(true);
    //            await Vision.PrepearBottomFlyCapture2(captureFlag, IsUseSiMo1, CurrentFeedTrayCol, SignalPanel.Signal.CurrentFeedTray, flyCaptureLists);
    //            SetFlyCapture();
    //            await Y_Axis.MoveToAsync(position, CancellationToken);
    //            LogInfo("Y轴完成移动飞拍");
    //            var hasProducts = Status.NozzleStatus.Select(x => x != TrayPointStatus.Empty && x != TrayPointStatus.NG).ToArray();
    //            var (isSuccess, results) = await Vision.GetBottomFlyCaptureResults1_Funcation(captureFlag, hasProducts);
    //            if (!isSuccess && !_inspectorOption.IsDryRunMode)
    //            {
    //                if (currentFlyReadCodeCount >= _inspectorOption.FlyReadCodeCount)//当读码飞拍次数达到设定次数
    //                {
    //                    for (int i = 0; i < results.Count(); i++)//True==强制跳过， 根据实际结果来判断,但是如果本来吸嘴上就没有产品就不判断了。
    //                    {
    //                        if (Status.NozzleStatus[i] != TrayPointStatus.Empty)
    //                        {
    //                            Status.NozzleStatus[i] = results[i].Quality == Quality.Ok ? TrayPointStatus.OK : TrayPointStatus.NG;
    //                        }
    //                    }
    //                }
    //                else
    //                {
    //                    return FlyStepState.ChongShi;
    //                }
    //                //LogError("下相机一次飞拍失败！");
    //                //FlaySnapError = true;
    //                //await Task.Delay(2000);
    //            }
    //            if (_inspectorOption.IsDryRunMode)
    //            {
    //                LogWarning("空跑模式，忽略下相机一次飞拍结果！");
    //                results = [new(), new(), new(), new(), new(), new(), new()];
    //            }
    //            LogInfo("R轴旋转偏移");

    //            #region 因为算法失败 补偿值很大，为了避免夹爪超行程报警，补偿设置为0
    //            var r1 = R1_Axis.GetTargetPosition(position) + (results[0].Quality == Quality.Ok ? results[0].Offset.Angle : 0);
    //            var r2 = R2_Axis.GetTargetPosition(position) + (results[1].Quality == Quality.Ok ? results[1].Offset.Angle : 0);
    //            var r3 = R3_Axis.GetTargetPosition(position) + (results[2].Quality == Quality.Ok ? results[2].Offset.Angle : 0);
    //            var r4 = R4_Axis.GetTargetPosition(position) + (results[3].Quality == Quality.Ok ? results[3].Offset.Angle : 0);
    //            var r5 = R5_Axis.GetTargetPosition(position) + (results[4].Quality == Quality.Ok ? results[4].Offset.Angle : 0);
    //            var r6 = R6_Axis.GetTargetPosition(position) + (results[5].Quality == Quality.Ok ? results[5].Offset.Angle : 0);
    //            var r7 = R7_Axis.GetTargetPosition(position) + (results[6].Quality == Quality.Ok ? results[6].Offset.Angle : 0);

    //            //var r1 = R1_Axis.GetTargetPosition(position) + results[6].Offset.Angle;
    //            //var r2 = R2_Axis.GetTargetPosition(position) + results[5].Offset.Angle;
    //            //var r3 = R3_Axis.GetTargetPosition(position) + results[4].Offset.Angle;
    //            //var r4 = R4_Axis.GetTargetPosition(position) + results[3].Offset.Angle;
    //            //var r5 = R5_Axis.GetTargetPosition(position) + results[2].Offset.Angle;
    //            //var r6 = R6_Axis.GetTargetPosition(position) + results[1].Offset.Angle;
    //            //var r7 = R7_Axis.GetTargetPosition(position) + results[0].Offset.Angle;
    //            #endregion

    //            #region TODO:因为算法失败 补偿值很大，为了避免夹爪超行程报警，补偿设置为0
    //            //SignalPanel.Signal.JawOffsets = results.Select(x => x.Offset.X).ToArray();
    //            SignalPanel.Signal.JawOffsets = results.Select(x => (x.Quality == Quality.Ok) ? x.Offset.X : 0).ToArray();
    //            #endregion
    //            var speed1 = R1_Axis.GetVelocityCurve(position);
    //            var speed2 = R2_Axis.GetVelocityCurve(position);
    //            var speed3 = R3_Axis.GetVelocityCurve(position);
    //            var speed4 = R4_Axis.GetVelocityCurve(position);
    //            var speed5 = R5_Axis.GetVelocityCurve(position);
    //            var speed6 = R6_Axis.GetVelocityCurve(position);
    //            var speed7 = R7_Axis.GetVelocityCurve(position);

    //            await Parallel.ForEachAsync([(R1_Axis, r1, speed1), (R2_Axis, r2, speed2), (R3_Axis, r3, speed3), (R4_Axis, r4, speed4), (R5_Axis, r5, speed5), (R6_Axis, r6, speed6), (R7_Axis, r7, speed7)], CancellationToken, async (x, t) => await x.Item1.MoveToAsync(x.Item2, x.Item3, t));
    //            LogInfo("R轴旋转偏移完成");
    //            Step = step + 1;
    //            return FlyStepState.ComplementOK;
    //        }

    //        /// <summary>
    //        /// X轴移动到撕膜位置,夹爪下降
    //        /// </summary>
    //        /// <param name="step"></param>
    //        /// <returns></returns>
    //        public async Task MoveXYZToSiMoWei(int step)
    //        {
    //            if (Step != step) return;
    //            OnStepChanged("移动到撕膜位");
    //            var JudgerFeeder = IsUseSiMo1 ? Feeder1 : Feeder2;
    //            await Judger.Sure(() => JudgerFeeder.Axis.IsDone, CancellationToken);//等待飞达移动完成
    //            if (!JudgerFeeder.CheckIsReady())//检测飞达未就绪
    //            {
    //                SignalPanel.Signal.FeedrNotReady = true;
    //                LogInfo($"撕膜位判断{JudgerFeeder.Name}未就绪");
    //                await Judger.Sure(() => SignalPanel.Signal.FeedrReadyDone);
    //                SignalPanel.Signal.FeedrNotReady = false;
    //                Step = 4;//回到第一次飞拍起始位，重新飞拍
    //                LogInfo($"从撕膜位回到第一次飞拍起始位，重新飞拍");
    //                return;
    //            }
    //            LogInfo("X轴开始移动到撕膜位置");
    //            string ps = IsUseSiMo1 ? XYR撕膜位1 : XYR撕膜位2;
    //            await Parallel.ForEachAsync([X_Axis, Y_Axis], CancellationToken, async (x, t) => await x.MoveToAsync(ps, t));
    //            LogInfo("Z轴下降到撕膜位置");
    //            var axis = Functions.SelectObjects(Z_Axises, Status.NozzleStatus.Select(x => x == TrayPointStatus.OK).ToList());
    //            await Parallel.ForEachAsync(axis, CancellationToken, async (x, t) => await x.MoveToAsync(IsUseSiMo1 ? Z撕膜位1 : Z撕膜位2, t));
    //            LogInfo("夹爪力矩值读值");
    //            _=CalcLiJu();
    //            LogInfo("通知撕膜模组搬运完成");
    //            //await Task.Delay(500);
    //            SignalPanel.Signal.BanYunCompleted = true;
    //            Step = step + 1; ;
    //        }

    //        public async Task WaitSiMoCompleted(int step)
    //        {
    //            if (Step != step) return;
    //            OnStepChanged("等待撕膜完成");
    //            LogInfo("等待撕膜完成信号");
    //            await Judger.Sure(() => SignalPanel.Signal.SiMoCompleted, CancellationToken, interval: 20);
    //            await Task.Delay(10);
    //            SignalPanel.Signal.BanYunCompleted = false;
    //            SignalPanel.Signal.SiMoCompleted = false;
    //            Step = step + 1; ;
    //        }

    //        /// <summary>
    //        /// Y轴撕膜后二次飞拍,并且直接移动到取料位置
    //        /// </summary>
    //        /// <param name="step"></param>
    //        /// <returns></returns>
    //        public async Task FeiPai2(int step)
    //        {
    //            if (Step != step) return;
    //            if (await CheckVacuoError()) return;
    //            OnStepChanged("二次飞拍");
    //            LogInfo("收到撕膜已完成信号，Z轴移动夹爪到飞拍位");
    //            await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z飞拍位, t));
    //            if (await CheckVacuoError()) return;
    //            LogInfo("Z轴已到飞拍位,XY轴开始移动到二次飞拍位置");
    //            string ps = IsUseSiMo1 ? X飞拍位1 : X飞拍位2;
    //            string ps2 = IsUseSiMo1 ? XYR撕膜位1 : XYR撕膜位2;
    //            await Task.WhenAll(X_Axis.MoveToAsync(ps, CancellationToken), Y_Axis.MoveToAsync(ps2, CancellationToken));
    //            LogInfo("XY轴已到飞拍位置,开始二次飞拍");
    //            SetFlyCapture();
    //            CaptureFlag captureFlag = IsUseSiMo1 ? CaptureFlag.Detect_1 : CaptureFlag.Detect_1;
    //            //await Vision.PrepearBottomFlyCapture(captureFlag, IsUseSiMo1, CurrentFeedTrayCol, SignalPanel.Signal.CurrentFeedTray);
    //            var flyCaptureLists = GetNozzleProductStateNumbers();
    //            await Vision.PrepearBottomFlyCapture2(captureFlag, IsUseSiMo1, CurrentFeedTrayCol, SignalPanel.Signal.CurrentFeedTray, flyCaptureLists);
    //            LogInfo("开始移动到飞拍2终点位置");
    //            await Y_Axis.MoveToAsync(Y飞拍起始位, CancellationToken);
    //            LogInfo("已移动到飞拍2终点位置, Y轴二次飞拍完成");
    //            //var (isSuccess, results) = await Vision.GetBottomFlyCaptureResults2(captureFlag, Status.NozzleStatus.Select(x => x != TrayPointStatus.Empty).ToArray());
    //            var hasProducts = Status.NozzleStatus.Select(x => x != TrayPointStatus.Empty && x != TrayPointStatus.NG).ToArray();
    //            var (isSuccess, results) = await Vision.GetBottomFlyCaptureResults2_Funcation(captureFlag, hasProducts);
    //            if (!isSuccess && !_inspectorOption.IsDryRunMode)
    //            {
    //                //FlaySnapError = true;
    //                //await Task.Delay(1000);
    //                LogError("下相机二次飞拍失败！");
    //                //return;
    //            }
    //            if (_inspectorOption.IsDryRunMode)
    //            {
    //                for (int i = 0; i < results.Length; i++)
    //                {
    //                    if (Status.NozzleStatus[i] != TrayPointStatus.Empty)
    //                        Status.NozzleStatus[i] = TrayPointStatus.CompletedOK;
    //                }
    //            }
    //            else
    //            {
    //                for (int i = 0; i < results.Length; i++)
    //                {
    //                    #region TODO 撕膜NG和无产品都不进行撕膜复检结果判断
    //                    if (Status.NozzleStatus[i] != TrayPointStatus.Empty && Status.NozzleStatus[i] != TrayPointStatus.NG)
    //                    {
    //                        Status.NozzleStatus[i] = results[i] ? TrayPointStatus.CompletedOK : TrayPointStatus.CompletedNG;
    //                    }
    //                    #endregion
    //                }
    //            }
    //            LogInfo("R轴到放料位");
    //            var destName = ProductDirection(CurrentFeedTrayCol) ? XYR取料位1 : XYR取料位2;
    //            await Parallel.ForEachAsync(R_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(destName, t));
    //            Step = step + 1; ;
    //        }

    //        /// <summary>
    //        /// 变距轴缩回, X轴移动到取料位置,夹爪放料:夹爪Z轴下降,吹真空,夹爪Z轴上升
    //        /// </summary>
    //        /// <param name="step"></param>
    //        /// <returns></returns>
    //        public async Task OKFangLiao(int step)
    //        {
    //            if (Step != step) return;
    //            OnStepChanged("OK放料");
    //            List<IServoAxis> axises = Functions.SelectObjects(Z_Axises, Status.NozzleStatus.Select(x => x == TrayPointStatus.CompletedOK).ToList());
    //            LogInfo("Z轴开始移动到飞拍位安全位");
    //            await Parallel.ForEachAsync(axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z飞拍位, t));
    //            LogInfo("Z轴移动到飞拍位安全位完成");
    //            var destName = ProductDirection(CurrentFeedTrayCol) ? XYR取料位1 : XYR取料位2;
    //            var offsetX = GetFeedTrayOffset(CurrentFeedTrayCol);
    //            var speedX = X_Axis.GetVelocityCurve(destName);
    //            var destX = X_Axis.GetTargetPosition(destName) + offsetX;
    //            LogInfo("X/Y轴开始移动到放料位，变距缩紧");
    //            await Task.WhenAll(
    //                X_Axis.MoveToAsync(destX, speedX, CancellationToken)
    //                .ContinueWith(x => LogInfo(X_Axis.Name + $"X已移动到放料位[{destX:F6}]")),
    //                Y_Axis.MoveToAsync(destName, CancellationToken)
    //                .ContinueWith(x => LogInfo(Y_Axis.Name + $"Y已移动到放料位")),
    //                JiaZhuaBianJu_Axis.MoveToAsync(BJ_缩紧位, CancellationToken).ContinueWith(x => LogInfo(JiaZhuaBianJu_Axis.Name + $"已移动到缩紧位"))
    //                );
    //            LogInfo("X/Y/变距已到放料位，Z轴下降到放料位");
    //            await Parallel.ForEachAsync(axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z放料位, t));
    //            List<Nozzle> nozzles = Functions.SelectObjects(Nozzles, Status.NozzleStatus.Select(x => x == TrayPointStatus.CompletedOK).ToList());
    //            LogInfo("Z轴已下降到放料位,开始破真空");
    //            await Parallel.ForEachAsync(nozzles, CancellationToken, async (x, t) =>
    //            {
    //                await x.BrokenAndCheckAsync();
    //            });
    //            //var t = Task.Run(async () =>
    //            //{
    //            //    await Parallel.ForEachAsync(nozzles, CancellationToken, async (x, t) =>
    //            //    {
    //            //        await Task.Delay(500);
    //            //        x.StopAsync();
    //            //    });
    //            //}, CancellationToken);
    //            for (int i = 0; i < Status.NozzleStatus.Length; i++)
    //            {
    //                if (Status.NozzleStatus[i] == TrayPointStatus.CompletedOK)
    //                {
    //                    Status.NozzleStatus[i] = TrayPointStatus.Empty;
    //                    FeedTray.Instance.SetTrayPointStatus(CurrentFeedTrayCol, i + 1, TrayPointStatus.CompletedOK);
    //                }
    //            }
    //            //await Task.Delay(1000);
    //            OnNozzelProductChanged();
    //            int okCount = nozzles.Count;
    //            //Status.OKCount += okCount;
    //            ProductCompleted?.SafeInvoke(this, (true, okCount));
    //            LogInfo("Z轴到待机位置");
    //            await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(待机位, t));
    //            for (int i = 0; i < nozzles.Count(); i++)
    //            {
    //                nozzles[i].StopAsync();
    //            }
    //            LogInfo("破真空完成");
    //            LogInfo("完成OK放料");
    //            Step = step + 1; ;
    //        }

    //        /// <summary>
    //        /// NG放料
    //        /// </summary>
    //        /// <param name="step"></param>
    //        /// <returns></returns>
    //        public async Task NGFangLiao(int step)
    //        {
    //            if (Step != step) return;
    //            OnStepChanged("NG放料");
    //            LogInfo("开始NG放料");
    //            bool hasNG = Status.NozzleStatus.Any(x => x == TrayPointStatus.CompletedNG || x == TrayPointStatus.NG);
    //            if (hasNG)
    //            {
    //                await MoveXYToOriginal();
    //                for (int i = 0; i < Status.NozzleStatus.Length; i++)
    //                {
    //                    bool isNG = Status.NozzleStatus[i] == TrayPointStatus.CompletedNG || Status.NozzleStatus[i] == TrayPointStatus.NG;
    //                    if (isNG)
    //                    {
    //                        if (!NGXiaoLiao.CheckIsTrayReady())
    //                        {
    //                            NGTrayNoReadyError = true;
    //                            LogError("NG料盘未就绪！");
    //                            await Task.Delay(1000);
    //                            return;
    //                        }
    //                        var nozzele = Nozzles[i];
    //                        var zaxis = Z_Axises[i];
    //                        int minRow = 1;
    //                        int maxCol = 3;
    //                        //if (i > 3)  //TODO 担心4-7吸嘴会有风险，现在没有1-7对应穴位没有风险
    //                        //{
    //                        //    maxCol = 4;
    //                        //}
    //                        //var item = NGTray.Instance.GetNext(minRow, maxCol);
    //                        var item = NGTray.Instance.GetNext2(minRow, maxCol);
    //                        if (item == null)
    //                        {
    //                            if (_inspectorOption.IsDryRunMode)
    //                            {
    //                                NGTray.Instance.Reset();
    //                                //item = NGTray.Instance.GetNext(minRow, maxCol);
    //                                item = NGTray.Instance.GetNext2(minRow, maxCol);
    //                            }
    //                            else
    //                            {
    //                                NGTrayFullError = true;
    //                                await Task.Delay(500);
    //                                return;
    //                            }
    //                        }
    //                        var (PointX, PointY) = item.GetPutPoint(X_Axis.GetTargetPosition(XY_NG下料位), Y_Axis.GetTargetPosition(XY_NG下料位));
    //                        var x = PointX;
    //                        var y = PointY + (i * _inspectorOption.JawDistance);
    //                        var speedx = X_Axis.GetVelocityCurve(XY_NG下料位);
    //                        var speedy = Y_Axis.GetVelocityCurve(XY_NG下料位);
    //                        if (x > X_Axis.GetTargetPosition(XY_NG下料避让位) && y > Y_Axis.GetTargetPosition(XY_NG下料避让位))
    //                        {
    //                            LogError("XY到放料NG点超限位，可能发生碰撞，请检查XY轴的NG下料避让点位设置");
    //                            IsAxisSaveAlarm = true;
    //                            await Task.Delay(2000);
    //                            return;
    //                        }
    //                        LogInfo("XY轴移动到放料NG点");
    //                        await Task.WhenAll(Y_Axis.MoveToAsync(y, speedy, CancellationToken), X_Axis.MoveToAsync(x, speedx, CancellationToken));
    //                        LogInfo("X/Y/已到NG放料位，R轴到NG放料位");
    //                        await Parallel.ForEachAsync(R_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(R_NG放料位, t));
    //                        LogInfo("R轴已到NG放料位,Z轴移动到放料NG点");
    //                        await zaxis.MoveToAsync(Z_NG放料位, CancellationToken);
    //                        LogInfo("Z轴已到放料NG点，吸嘴破真空");
    //                        nozzele.BrokenAsync();
    //                        item.Put();
    //                        await Task.Delay(200);
    //                        if (!await nozzele.StopAndCheckAsync() && !_inspectorOption.IsDryRunMode)
    //                        {
    //                            LogError("吸嘴破真空失败！");
    //                            await Task.Delay(500);
    //                            return;
    //                        }
    //                        LogInfo("Z轴移动到放料待机位");
    //                        await zaxis.MoveToAsync(Z待机位, CancellationToken);
    //                        Status.NozzleStatus[i] = TrayPointStatus.Empty;
    //                        FeedTray.Instance.SetTrayPointStatus(CurrentFeedTrayCol, i + 1, TrayPointStatus.Empty);
    //                        NGTray.Instance.OnNGTrayItemStatusChanged(item.Row, item.Col, TrayPointStatus.CompletedNG);
    //                        //Status.NGCount++;
    //                        ProductCompleted?.SafeInvoke(this, (false, 1));
    //                    }
    //                }
    //            }
    //            CurrentFeedTrayCol = GetNextColumn(CurrentFeedTrayCol, out bool reverse, out bool isNewTray);
    //            if (isNewTray)
    //            {
    //                if (!_inspectorOption.IsDryRunMode)
    //                {
    //                    SignalPanel.Signal.FeedTrayCompleted = true;
    //                    LogInfo("入料盘取料完成,XYZ到待机位");
    //                    await Task.Delay(10);
    //                }
    //                await MoveXYToOriginal();
    //            }
    //            Step = 0;
    //        }

    //        /// <summary>
    //        /// 获取取料列数
    //        /// </summary>
    //        /// <param name="currentCol"></param>
    //        /// <param name="reverse">是否切换方向：奇数列切换到偶数列</param>
    //        /// <param name="isNewTray">是否换新Tray</param>
    //        /// <returns></returns>
    //        private int GetNextColumn(int currentFeedTrayCol, out bool reverse, out bool isNewTray)
    //        {
    //            reverse = false;
    //            isNewTray = false;
    //            var newCol = currentFeedTrayCol + 2;
    //            if (newCol > FeedTray.Instance.Col)
    //            {
    //                if (newCol % 2 == 1)
    //                {
    //                    reverse = true;
    //                    newCol = 2;
    //                }
    //                else
    //                {
    //                    isNewTray = true;
    //                    newCol = 1;
    //                }
    //            }
    //            return newCol;
    //        }

    //        public async Task BottomCameraRotationCenterCalibration(bool isUseSiMo1, CancellationToken cancellationToken, bool isAutoSave, bool isRotationCenterCalibration)
    //        {
    //            if (!_isInit) return;
    //            OnStepChanged("旋转中心标定飞拍1");
    //            string p = isUseSiMo1 ? X飞拍位1 : X飞拍位2;
    //            LogInfo("移动XY到飞拍位置,夹爪变距张开");
    //            await Task.WhenAll(X_Axis.MoveToAsync(p, cancellationToken), Y_Axis.MoveToAsync(Y飞拍起始位, cancellationToken), Camera_Axis.MoveToAsync(p, cancellationToken), JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, cancellationToken));
    //            LogInfo("XY已移动到飞拍位置，R轴旋转到撕膜位");
    //            string position = isUseSiMo1 ? XYR撕膜位1 : XYR撕膜位2;
    //            await Parallel.ForEachAsync(R_Axises, cancellationToken, async (x, t) => await x.MoveToAsync(position, cancellationToken));
    //            LogInfo("R轴已旋转到撕膜位，Z轴到飞拍位");
    //            await Parallel.ForEachAsync(Z_Axises, cancellationToken, async (x, t) => await x.MoveToAsync(Z飞拍位, cancellationToken));
    //            LogInfo("Z轴已到飞拍位，Y轴移动飞拍");
    //            string barcode = $"Calib_{DateTime.Now:HHmmss}";
    //            await Vision.StartAsync(barcode);
    //            CaptureFlag captureFlag = isUseSiMo1 ? CaptureFlag.Calib_0 : CaptureFlag.Calib_1;
    //            await Vision.PrepearBottomFlyCapture(captureFlag, IsUseSiMo1, CurrentFeedTrayCol, barcode);
    //            SetFlyCapture();
    //            await Y_Axis.MoveToAsync(position, cancellationToken);
    //            LogInfo("飞拍1结束");

    //            var b = await Vision.BottomRotationCenterCalibration(isUseSiMo1, captureFlag, 1, isAutoSave, isRotationCenterCalibration);
    //            if (!b)
    //            {
    //                LogError("标定飞拍1失败"); return;
    //            }
    //            await Task.Delay(200);
    //            LogInfo("Y轴移动到飞拍起始位");
    //            await Y_Axis.MoveToAsync(Y飞拍起始位, cancellationToken);

    //            LogInfo("R轴旋转180°");
    //            double angle = 180;
    //            var r1 = R1_Axis.GetTargetPosition(position) + angle;
    //            var r2 = R2_Axis.GetTargetPosition(position) + angle;
    //            var r3 = R3_Axis.GetTargetPosition(position) + angle;
    //            var r4 = R4_Axis.GetTargetPosition(position) + angle;
    //            var r5 = R5_Axis.GetTargetPosition(position) + angle;
    //            var r6 = R6_Axis.GetTargetPosition(position) + angle;
    //            var r7 = R7_Axis.GetTargetPosition(position) + angle;
    //            var speed1 = R1_Axis.GetVelocityCurve(position);
    //            var speed2 = R2_Axis.GetVelocityCurve(position);
    //            var speed3 = R3_Axis.GetVelocityCurve(position);
    //            var speed4 = R4_Axis.GetVelocityCurve(position);
    //            var speed5 = R5_Axis.GetVelocityCurve(position);
    //            var speed6 = R6_Axis.GetVelocityCurve(position);
    //            var speed7 = R7_Axis.GetVelocityCurve(position);

    //            await Parallel.ForEachAsync([(R1_Axis, r1, speed1), (R2_Axis, r2, speed2), (R3_Axis, r3, speed3), (R4_Axis, r4, speed4), (R5_Axis, r5, speed5), (R6_Axis, r6, speed6), (R7_Axis, r7, speed7)], cancellationToken, async (x, t) => await x.Item1.MoveToAsync(x.Item2, x.Item3, t));
    //            LogInfo("R轴旋转180°完成");

    //            await Task.Delay(200);
    //            LogInfo("Y轴已到起始位，开始飞拍2");
    //            CaptureFlag captureFlag2 = isUseSiMo1 ? CaptureFlag.Calib_1 : CaptureFlag.Calib_0;
    //            await Vision.PrepearBottomFlyCapture(captureFlag2, IsUseSiMo1, 2, barcode);
    //            SetFlyCapture();
    //            await Y_Axis.MoveToAsync(position, cancellationToken);
    //            LogInfo("飞拍2结束,R轴旋转到撕膜位");
    //            await Parallel.ForEachAsync(R_Axises, cancellationToken, async (x, t) => await x.MoveToAsync(position, cancellationToken));
    //            if (!await Vision.BottomRotationCenterCalibration(isUseSiMo1, captureFlag2, 2, isAutoSave, isRotationCenterCalibration))
    //            {
    //                LogError("标定飞拍2失败"); return;
    //            }
    //        }

    //        /// <summary>
    //        /// 移动XY轴到指定坐标
    //        /// </summary>
    //        /// <param name="destX"></param>
    //        /// <param name="destY"></param>
    //        /// <returns></returns>
    //        public async Task MoveXYAxis(double destX, double destY, CancellationToken cancellationToken)
    //        {
    //            if (!_isInit)
    //                throw new Exception("移动XY轴前请完成设备初始化!");
    //            if (!IsZAxiesSave())
    //                throw new Exception("移动XY轴时Z轴不在安全位置!");
    //            await Parallel.ForEachAsync([(X_Axis, destX), (Y_Axis, destY)], cancellationToken, async (x, t) => { await x.Item1.MoveToAsync(x.Item2, null, t); });
    //        }

    //        public async Task MoveXYToOriginal()
    //        {
    //            LogInfo("Z轴移动到待机位");
    //            await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) =>
    //            {
    //                await x.MoveToAsync(Z待机位, t);
    //            });
    //            LogInfo("XY轴移动到待机位");
    //            await Task.WhenAll(
    //                X_Axis.MoveToAsync(X待机位, CancellationToken)
    //                .ContinueWith(x => LogInfo(X_Axis.Name + $"已移动到待机位")),
    //                Y_Axis.MoveToAsync(Y待机位, CancellationToken)
    //                .ContinueWith(x => LogInfo(Y_Axis.Name + $"已移动到待机位")),
    //                JiaZhuaBianJu_Axis.MoveToAsync(BJ_张开位, CancellationToken)
    //                .ContinueWith(x => LogInfo(JiaZhuaBianJu_Axis.Name + "变距已移动到张开位"))
    //                );
    //        }

    //        /// <summary>
    //        /// 获取当前产品角度,旋转R轴,单排0°,双排180°
    //        /// </summary>
    //        /// <returns></returns>
    //        public bool ProductDirection(int col)
    //        {
    //            return ((col + 1) % 2) == 0;
    //        }

    //        /// <summary>
    //        /// 获取入料盘取料时X坐标偏移,和当前列产品状态
    //        /// </summary>
    //        /// <returns></returns>
    //        public double GetFeedTrayOffset(int col)
    //        {
    //            var px = -((col - 1) / 2) * FeedTray.Instance.ColDistance;
    //            return px;
    //        }

    //        /// <summary>
    //        /// 获取入料盘取料时Y坐标偏移
    //        /// </summary>
    //        /// <returns></returns>
    //        public double GetFeedTrayOffsetY(int row)
    //        {
    //            var py = row * FeedTray.Instance.RowDistance;
    //            return py;
    //        }

    //        public void SetFlyCapture()
    //        {
    //            double[] positions = [
    //                Y_Axis.GetTargetPosition(Y夹爪1飞拍位),
    //                Y_Axis.GetTargetPosition(Y夹爪2飞拍位),
    //                Y_Axis.GetTargetPosition(Y夹爪3飞拍位),
    //                Y_Axis.GetTargetPosition(Y夹爪4飞拍位),
    //                Y_Axis.GetTargetPosition(Y夹爪5飞拍位),
    //                Y_Axis.GetTargetPosition(Y夹爪6飞拍位),
    //                Y_Axis.GetTargetPosition(Y夹爪7飞拍位),
    //            ];
    //            int length = positions.Length;
    //            double rate = Y_Axis.Equivalent;
    //            double current = Y_Axis.Current;
    //            Electronic.Controller.SetExtraEncoder(0);
    //            double[] capturePoint = new double[length];
    //            for (int i = 0; i < length; i++)
    //            {
    //                capturePoint[i] = (positions[i] - current) * rate;
    //            }
    //            if (current > positions[6])
    //            {
    //                double[] temp = new double[length];
    //                Array.Copy(capturePoint, temp, length);
    //                for (int i = 0; i < length; i++)
    //                {
    //                    capturePoint[i] = temp[6 - i];
    //                }
    //            }
    //            Electronic.Controller.SetupTriggerTable(5, capturePoint);
    //        }

    //        public void SetFlyCapture2(List<double> positions)
    //        {
    //            int length = positions.Count;
    //            double rate = Y_Axis.Equivalent;
    //            Electronic.Controller.SetExtraEncoder(0);
    //            double[] capturePoint = new double[length];
    //            for (int i = 0; i < length; i++)
    //            {
    //                capturePoint[i] = (positions[i]) * rate;
    //            }
    //            Electronic.Controller.SetupTriggerTable(4, capturePoint);
    //        }

    //        public void ClearFlyCapture()
    //        {
    //            Electronic.Controller.ClearTriggerTable(4);
    //            Electronic.Controller.ClearTriggerTable(5);
    //        }

    //        public void ClearAlarm()
    //        {
    //            IsAxisSaveAlarm = false;
    //            FeedTrayError = false;
    //            FlaySnapError = false;
    //            NGTrayFullError = false;
    //            NozzelVaccumError = false;
    //        }

    //        public void OnStepChanged(string step)
    //        {
    //            StepsChanged?.SafeInvoke(this, step);
    //        }

    //        public void OnNozzelProductChanged()
    //        {
    //            NozzelsProductChanged?.SafeInvoke(this, Status.NozzleStatus);
    //        }

    //        public bool IsZAxiesSave()
    //        {
    //            return Z_Axises.All(x => x.Current <= x.GetTargetPosition(Z飞拍位) + 0.1);
    //        }

    //        protected override async void OnStopped()
    //        {
    //            var axies = this.Automatics.Where(x => x is DmcAxis).Cast<DmcAxis>().ToArray();
    //            await Parallel.ForEachAsync(axies, cancellationToken: default, async (x, t) => await x.PauseAsync());
    //            Status.ZAxisPositions = Z_Axises.Select(x => x.Current).ToArray();
    //            Status.RAxisPositions = R_Axises.Select(x => x.Current).ToArray();
    //            FeedTray.Instance.Save();
    //            Status.Save();
    //        }

    //        protected override async Task PreRunning()
    //        {
    //            try
    //            {
    //                foreach (var automatic in Automatics)
    //                {
    //                    if (automatic is DmcAxis dmcAxis)
    //                    {
    //                        await dmcAxis.InitializeAsync();
    //                    }
    //                }
    //                Status = RunningStatus.GetRecord<BanYunRunningStatus>("BanYun.json");
    //                var repository = Service.GetRequiredService<IOptionRepository>();
    //                _inspectorOption = repository.Get<InspectorOption>();
    //                Option = Recipe.Get<BanYunStationOption>(Id);
    //                if (!_isInit)
    //                {
    //                    _isInit = await InitializeStation(CancellationToken);
    //                }
    //                else
    //                {
    //                    for (int i = 0; i < Z_Axises.Count; i++)
    //                    {
    //                        if (Math.Abs(Z_Axises[i].Current - Status.ZAxisPositions[i]) > 1)
    //                        {
    //                            await Z_Axises[i].MoveToAsync(Z待机位, CancellationToken);
    //                        }
    //                    }
    //                }
    //            }
    //            catch (Exception e)
    //            {
    //                LogError(e);
    //                Root.Stop();
    //            }
    //        }

    //        public override async Task InitializeAsync()
    //        {
    //            var repository = Service.GetRequiredService<IOptionRepository>();
    //            _inspectorOption = repository.Get<InspectorOption>();
    //            Status = RunningStatus.GetRecord<BanYunRunningStatus>("BanYun.json");
    //            await base.InitializeAsync();
    //        }

    //        /// <summary>
    //        /// 检查是否吸真空异常
    //        /// </summary>
    //        /// <returns></returns>
    //        public async Task<bool> CheckVacuoError()
    //        {
    //            if (_inspectorOption.IsDryRunMode)
    //            {
    //                return false;
    //            }
    //            var nozzles = Functions.SelectObjects(Nozzles, Status.NozzleStatus.Select(x => x == TrayPointStatus.OK).ToList());
    //            var tasks = new List<Task<bool>>();
    //            foreach (var item in nozzles)
    //            {
    //                tasks.Add(item.SuckAndCheckAsync());
    //            }
    //            //await Task.Delay(_inspectorOption.VaccumOnDelay);
    //            var result = await Task.WhenAll(tasks);
    //            if (!result.All(x => x))
    //            {
    //                LogError("吸嘴取产品真空报警。");
    //                await Task.Delay(500);
    //                return true;
    //            }
    //            return false;
    //        }

    //        /// <summary>
    //        /// 获取吸嘴上有产品的状态
    //        /// </summary>
    //        /// <returns></returns>
    //        List<int> GetNozzleProductStateNumbers(bool isIsReverse = false)
    //        {
    //            List<int> numbers = new List<int>();
    //            if (isIsReverse)//吸嘴7-1
    //            {
    //                for (int i = 0; i < Status.NozzleStatus.Count(); i++)
    //                {
    //                    var state = Status.NozzleStatus[i];
    //                    if (state != TrayPointStatus.Empty && state != TrayPointStatus.NG)
    //                    {
    //                        int number = i + 1;
    //                        number = Math.Abs(number - 8);
    //                        numbers.Add(number);
    //                    }
    //                }
    //            }
    //            else //吸嘴1-7
    //            {
    //                for (int i = 0; i < Status.NozzleStatus.Count(); i++)
    //                {
    //                    var state = Status.NozzleStatus[i];
    //                    if (state != TrayPointStatus.Empty && state != TrayPointStatus.NG)
    //                    {
    //                        numbers.Add(i + 1);
    //                    }
    //                }
    //            }
    //            return numbers;
    //        }

    //        //public async Task FATAsync(CancellationToken cancellationToken)
    //        //{
    //        //    LogInfo("等待2000ms");
    //        //    CurrentFeedTrayCol = 1;
    //        //    //开始取料
    //        //    LogInfo("Z轴下降到取料位");
    //        //    await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z取料位, t));
    //        //    // var tasks = new List<Task<bool>>();
    //        //    foreach (var item in Nozzles)
    //        //    {
    //        //        //tasks.Add(item.SuckAndCheckAsync());
    //        //        item.SuckAsync();
    //        //    }
    //        //    await Task.Delay(1000);

    //        //    await Parallel.ForEachAsync(Nozzles, CancellationToken, async (x, t) =>
    //        //    {
    //        //        x.SuckAsync();
    //        //    });
    //        //    await Task.Delay(1000);

    //        //    //   var result = await Task.WhenAll(tasks);
    //        //    bool[] result = [true, true, true, true, true, true, true];
    //        //    await Task.Delay(_inspectorOption.VaccumOnDelay);
    //        //    if (_inspectorOption.IsDryRunMode)
    //        //    {
    //        //        for (int i = 0; i < result.Count(); i++)
    //        //        {
    //        //            result[i] = true;
    //        //        }
    //        //        LogWarning("空跑模式吸嘴强制OK!");
    //        //    }
    //        //    if (result.Any(x => !x)) return;
    //        //    Status.NozzleProducts = [TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK];
    //        //    LogInfo("Z轴开始上升到飞拍位");
    //        //    await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z飞拍位, t));
    //        //    await Task.Delay(100);


    //        //    LogInfo("开始OK放料,Z轴下降到放料位");
    //        //    await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(Z取料位, t));
    //        //    //List<Nozzle> nozzles = Functions.SelectObjects(Nozzles, Status.SiMoResults.ToList());
    //        //    await Parallel.ForEachAsync(Nozzles, CancellationToken, async (x, t) =>
    //        //    {
    //        //        x.BrokenAsync();
    //        //    });
    //        //    var t = Task.Run(async () =>
    //        //    {
    //        //        await Parallel.ForEachAsync(Nozzles, CancellationToken, async (x, t) =>
    //        //        {
    //        //            await Task.Delay(500);
    //        //            x.StopAsync();
    //        //        });
    //        //    }, CancellationToken);
    //        //    if (_inspectorOption.IsDryRunMode)
    //        //    {
    //        //        for (int i = 0; i < result.Count(); i++)
    //        //        {
    //        //            result[i] = true;
    //        //        }
    //        //        LogWarning("空跑模式吸嘴强制OK!");
    //        //    }
    //        //    if (!result.All(x => x))
    //        //    {
    //        //        return;
    //        //    }
    //        //    Status.NozzleProducts = [TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK, TrayPointStatus.OK];
    //        //    OnNozzelProductChanged();
    //        //    LogInfo("Z轴到待机位置");
    //        //    await Parallel.ForEachAsync(Z_Axises, CancellationToken, async (x, t) => await x.MoveToAsync(待机位, t));
    //        //    LogInfo("完成OK放料");
    //        //}
    //        ushort[] nodeNums = new ushort[] { 1010, 1012, 1014, 1016, 1018, 1020, 1022 };
    //        List<LijuModel> _lijuModels = new List<LijuModel>();

    //        /// <summary>
    //        /// 计算力矩
    //        /// </summary>
    //        public async Task CalcLiJu()
    //        {
    //            await Task.Run(async () =>
    //            {
    //                await Task.Delay(500);
    //                _lijuModels.Clear();
    //                for (int i = 0; i < nodeNums.Count(); i++)
    //                {
    //                    var nodeNum = nodeNums[i];
    //                    short outValue = 0;
    //                    Electronic.Controller.GetNodeOd(0, 2, nodeNum, 0x6077, 0, 16, ref outValue);
    //                    var _lijuModel = new LijuModel() { Number = i + 1, Current = outValue };
    //                    _lijuModel.Calc();
    //                    _lijuModels.Add(_lijuModel);
    //                }
    //                LiJuChanged?.Invoke(this, _lijuModels);
    //            });
    //        }
    //        /// <summary>
    //        /// 上相机飞拍读码
    //        /// </summary>
    //        public async Task<FlyStepState> FeiPai3(int step, int currentFlyReadCodeCount)
    //        {
    //            // X===> -     +
    //            //       -
    //            // Y===>
    //            //       +
    //            if (Step != step) return FlyStepState.TiaoGuo;
    //            //判断当前列是否有料，无料继续判断下一列
    //            while (!IsCheckProductState())
    //            {
    //                LogWarning($"当前料盘列{CurrentFeedTrayCol}无产品。");
    //                CurrentFeedTrayCol = GetNextColumn(CurrentFeedTrayCol, out bool reverse, out bool isNewTray);
    //                LogWarning($"寻找下一料盘列{CurrentFeedTrayCol}.");
    //                if (isNewTray)
    //                {
    //                    SignalPanel.Signal.FeedTrayCompleted = true;
    //                    LogInfo("入料盘取料完成,XYZ到待机位");
    //                    await Task.Delay(10);
    //                    await MoveXYToOriginal();
    //                    Step = 0;
    //                    return FlyStepState.TiaoGuo;
    //                }
    //            }
    //            var colStatus = FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1];
    //            var destName = ProductDirection(CurrentFeedTrayCol) ? 上相机读码位1 : 上相机读码位2;
    //            var offsetX = GetFeedTrayOffset(CurrentFeedTrayCol);//X间隔的距离
    //            var speedX = X_Axis.GetVelocityCurve(destName);
    //            var destX = X_Axis.GetTargetPosition(destName) + offsetX;
    //            await Task.WhenAll(X_Axis.MoveToAsync(destX, speedX, CancellationToken), Y_Axis.MoveToAsync(destName, CancellationToken));
    //            var endPost = Y_Axis.Current + FeedTray.Instance.RowDistance * 7 + 10;//飞拍结束位，以最后结束位加10ms
    //            var offsetY1 = GetFeedTrayOffsetY(0) + 1;//防止第一个位置就触发取图
    //            var offsetY2 = GetFeedTrayOffsetY(1);
    //            var offsetY3 = GetFeedTrayOffsetY(2);
    //            var offsetY4 = GetFeedTrayOffsetY(3);
    //            var offsetY5 = GetFeedTrayOffsetY(4);
    //            var offsetY6 = GetFeedTrayOffsetY(5);
    //            var offsetY7 = GetFeedTrayOffsetY(6);

    //            //查找当前列那些产品需要飞拍的
    //            List<int> flyCaptureLists = new List<int>();
    //            bool[] hasProducts = new bool[colStatus.Items.Count()];
    //            for (int i = 0; i < colStatus.Items.Count(); i++)
    //            {
    //                hasProducts[i] = colStatus.Items[i].Status != TrayPointStatus.Empty ? true : false;
    //                if (colStatus.Items[i].Status != TrayPointStatus.Empty)
    //                {
    //                    int number = i + 1;
    //                    number = Math.Abs(number - 8);
    //                    flyCaptureLists.Add(number);
    //                }
    //            }
    //            await Vision.PrepearUpFlyCapture(IsUseSiMo1, CurrentFeedTrayCol, flyCaptureLists, SignalPanel.Signal.CurrentFeedTray);
    //            SetFlyCapture2(new List<double> { offsetY1, offsetY2, offsetY3, offsetY4, offsetY5, offsetY6, offsetY7 });
    //            var velocityCurve = Y_Axis.GetVelocityCurve(destName);
    //            await Y_Axis.MoveToAsync(endPost, velocityCurve, CancellationToken);
    //            var (isSuccess, results) = await Vision.GetUpFlyCaptureResults_Funcation(hasProducts);
    //            if (isSuccess)//读码成功的；直接赋值
    //            {
    //                for (int i = 0; i < results.Count(); i++)
    //                {
    //                    if (colStatus.Items[i].Status != TrayPointStatus.Empty)
    //                    {
    //                        colStatus.Items[i].Status = results[i].Quality == Quality.Ok ? TrayPointStatus.OK : TrayPointStatus.NG;
    //                    }
    //                }
    //                FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1] = colStatus;
    //            }
    //            else
    //            {
    //                if (currentFlyReadCodeCount >= _inspectorOption.FlyReadCodeCount)//当读码飞拍次数达到设定次数
    //                {
    //                    for (int i = 0; i < results.Count(); i++)//根据实际结果来判断,但是如果本来列里面就没有产品就不判断了。
    //                    {
    //                        if (colStatus.Items[i].Status != TrayPointStatus.Empty)
    //                        {
    //                            colStatus.Items[i].Status = results[i].Quality == Quality.Ok ? TrayPointStatus.OK : TrayPointStatus.NG;
    //                        }
    //                    }
    //                    FeedTray.Instance.FeedTrayColunms[CurrentFeedTrayCol - 1] = colStatus;
    //                }
    //                else
    //                {
    //                    return FlyStepState.ChongShi;
    //                }
    //            }
    //            Step = 1;//直接去取料等待流程
    //            return FlyStepState.ComplementOK;
    //        }
    //    }
    //}
    #endregion
}
